diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index c4f4e686403b..06d0d3152a69 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); } diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 4a60f2368771..931e0a72e471 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -149,7 +149,8 @@ protected: virtual PRIntn GetSkipSides() const; - virtual void ComputeFinalSize(nsBlockReflowState& aState, + virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); void MarkEmptyLines(nsIPresContext& aPresContext); @@ -286,6 +287,8 @@ protected: void RenumberLists(); + void UpdateBulletPosition(); + void ReflowBullet(nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index c4f4e686403b..06d0d3152a69 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); } diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index c4f4e686403b..06d0d3152a69 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); } diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index c4f4e686403b..06d0d3152a69 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); } diff --git a/layout/html/base/src/nsBlockFrame.h b/layout/html/base/src/nsBlockFrame.h index 4a60f2368771..931e0a72e471 100644 --- a/layout/html/base/src/nsBlockFrame.h +++ b/layout/html/base/src/nsBlockFrame.h @@ -149,7 +149,8 @@ protected: virtual PRIntn GetSkipSides() const; - virtual void ComputeFinalSize(nsBlockReflowState& aState, + virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); void MarkEmptyLines(nsIPresContext& aPresContext); @@ -286,6 +287,8 @@ protected: void RenumberLists(); + void UpdateBulletPosition(); + void ReflowBullet(nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index c4f4e686403b..06d0d3152a69 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); } diff --git a/layout/html/base/src/nsBlockReflowState.h b/layout/html/base/src/nsBlockReflowState.h index c4f4e686403b..06d0d3152a69 100644 --- a/layout/html/base/src/nsBlockReflowState.h +++ b/layout/html/base/src/nsBlockReflowState.h @@ -22,7 +22,6 @@ #include "nsBulletFrame.h" #include "nsLineBox.h" -#include "nsFrameReflowState.h" #include "nsLineLayout.h" #include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" @@ -95,6 +94,7 @@ static const char* kReflowCommandType[] = { "PullupReflow", "PushReflow", "CheckPullupReflow", + "ReflowDirty", "UserDefined", }; #endif @@ -104,11 +104,10 @@ static void DumpStyleGeneaology(nsIFrame* aFrame, const char* gap) { fputs(gap, stdout); - aFrame->ListTag(stdout); - fputs(name, out); + nsFrame::ListTag(stdout, aFrame); printf(": "); nsIStyleContext* sc; - aFrame->GetStyleContext(sc); + aFrame->GetStyleContext(&sc); while (nsnull != sc) { nsIStyleContext* psc; printf("%p ", sc); @@ -173,10 +172,11 @@ RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus) //---------------------------------------------------------------------- -class nsBlockReflowState : public nsFrameReflowState { +class nsBlockReflowState { public: - nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, + nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout); @@ -203,13 +203,20 @@ public: PRBool IsLeftMostChild(nsIFrame* aFrame); PRBool IsAdjacentWithTop() const { - return mY == mBorderPadding.top; + return mY == mReflowState.mComputedBorderPadding.top; } PRBool ShouldApplyTopMargin() const { return mIsMarginRoot || !IsAdjacentWithTop(); } + const nsMargin& BorderPadding() const { + return mReflowState.mComputedBorderPadding; + } + + nsIPresContext& mPresContext; + const nsHTMLReflowState& mReflowState; + nsLineLayout* mLineLayout; nsInlineReflow* mInlineReflow; @@ -223,17 +230,12 @@ public: nsBlockFrame* mRunInFromFrame; nsBlockFrame* mRunInToFrame; - PRUint8 mTextAlign; - - PRUintn mPrevMarginFlags; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; PRBool mUnconstrainedHeight; nscoord mY; nscoord mKidXMost; - nscoord mAscent, mDescent; // Previous child. This is used when pulling up a frame to update // the sibling list. @@ -248,6 +250,33 @@ public: nsRect mAvailSpaceRect; nscoord mMinLineHeight; + + PRBool mComputeMaxElementSize; + nsSize mMaxElementSize; + + // The content area to reflow child frames within. The x/y + // coordinates are known to be mBorderPadding.left and + // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE + // if the container reflowing this frame has given the frame an + // unconstrained area. + nsSize mContentArea; + + // Our wrapping behavior + PRBool mNoWrap; + + // The previous child frames collapsed bottom margin value. + nscoord mPrevBottomMargin; + + nsIFrame* mNextRCFrame; + + // Is this frame a root for margin collapsing? + PRBool mIsMarginRoot; + + // The computed collapsed top margin value that the frame did not + // apply but is passing out to the frames parent so that the parent + // can perform generational margin collapsing. This value ends up + // being copied into the nsHTMLReflowMetrics.mCarriedOutTopMargin. + nscoord mCarriedOutTopMargin; }; // XXX This is vile. Make it go away @@ -264,11 +293,18 @@ nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) //---------------------------------------------------------------------- -nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, +nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, + nsIPresContext& aPresContext, + nsBlockFrame* aFrame, const nsHTMLReflowMetrics& aMetrics, nsLineLayout* aLineLayout) - : nsFrameReflowState(aPresContext, aReflowState, aMetrics) + : mPresContext(aPresContext), + mReflowState(aReflowState), + mBlock(aFrame), + mPrevBottomMargin(0), + mNextRCFrame(nsnull), + mIsMarginRoot(PR_FALSE), + mCarriedOutTopMargin(0) { mInlineReflow = nsnull; @@ -278,81 +314,108 @@ nsBlockReflowState::nsBlockReflowState(nsIPresContext& aPresContext, // Translate into our content area and then save the // coordinate system origin for later. - mSpaceManager->Translate(mBorderPadding.left, mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(borderPadding.left, borderPadding.top); mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY); mReflowStatus = NS_FRAME_COMPLETE; mPresContext = aPresContext; - mBlock = (nsBlockFrame*) frame; mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; mRunInFromFrame = nsnull; mRunInToFrame = nsnull; - mY = mAscent = mDescent = 0; - mUnconstrainedWidth = availableWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = availableHeight == NS_UNCONSTRAINEDSIZE; +#if 0 + // Compute "content area" + mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; + mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; #ifdef NS_DEBUG - if (!mUnconstrainedWidth && (availableWidth > 100000)) { + if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || + (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableWidth > 100000) { - availableWidth = NS_UNCONSTRAINEDSIZE; + printf(": bad parent: computed size is %d(0x%x),%d(0x%x)\n", + aReflowState.computedWidth, aReflowState.computedWidth, + aReflowState.computedHeight, aReflowState.computedHeight); + if (aReflowState.computedWidth > 200000) { mUnconstrainedWidth = PR_TRUE; } - } - if (!mUnconstrainedHeight && (availableHeight > 100000)) { - mBlock->ListTag(stdout); - printf(": bad parent: maxSize WAS %d,%d\n", availableWidth, availableHeight); - if (availableHeight > 100000) { - availableHeight = NS_UNCONSTRAINEDSIZE; + if (aReflowState.computedHeight > 200000) { mUnconstrainedHeight = PR_TRUE; } } +#endif #endif - mTextAlign = mStyleText->mTextAlign; - - nscoord lr = mBorderPadding.left + mBorderPadding.right; - mY = mBorderPadding.top; - - if (HaveFixedContentWidth()) { - // The CSS2 spec says that the width attribute defines the width - // of the "content area" which does not include the border - // padding. So we add those back in. - mBorderArea.width = computedWidth + lr; - mContentArea.width = computedWidth; + // Compute content area width (the content area is inside the border + // and padding) + mUnconstrainedWidth = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedWidth) { + mContentArea.width = aReflowState.computedWidth; } else { - if (mUnconstrainedWidth) { - mBorderArea.width = NS_UNCONSTRAINEDSIZE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { mContentArea.width = NS_UNCONSTRAINEDSIZE; + mUnconstrainedWidth = PR_TRUE; } else { - mBorderArea.width = availableWidth; - mContentArea.width = availableWidth - lr; + nscoord lr = borderPadding.left + borderPadding.right; + mContentArea.width = aReflowState.availableWidth - lr; } } - mBorderArea.height = availableHeight; - mContentArea.height = availableHeight; - mBottomEdge = availableHeight; - if (!mUnconstrainedHeight) { - mBottomEdge -= mBorderPadding.bottom; + // Compute content area height. Unlike the width, if we have a + // specified style height we ignore it since extra content is + // managed by the "overflow" property. When we don't have a + // specified style height then we may end up limiting our height if + // the availableHeight is constrained (this situation occurs when we + // are paginated). + mUnconstrainedHeight = PR_FALSE; + if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { + mContentArea.height = aReflowState.availableHeight; + mUnconstrainedHeight = PR_TRUE; } + else { + // Use constrained height + nscoord tb = borderPadding.top + borderPadding.bottom; + mContentArea.height = aReflowState.availableHeight - tb; + } + + mY = borderPadding.top; + mBottomEdge = mContentArea.height; mCurrentBand.Init(mSpaceManager, mContentArea); mPrevChild = nsnull; mCurrentLine = nsnull; mPrevLine = nsnull; + + const nsStyleText* styleText; + mBlock->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) styleText); + switch (styleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + + mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;; + mMaxElementSize.SizeTo(0, 0); + + if ((0 != borderPadding.top) || (0 != borderPadding.bottom)) { + mIsMarginRoot = PR_TRUE; + } } nsBlockReflowState::~nsBlockReflowState() { // Restore the coordinate system - mSpaceManager->Translate(-mBorderPadding.left, -mBorderPadding.top); + const nsMargin& borderPadding = BorderPadding(); + mSpaceManager->Translate(-borderPadding.left, -borderPadding.top); } // Get the available reflow space for the current y coordinate. The @@ -371,7 +434,7 @@ nsBlockReflowState::GetAvailableSpace() "bad coord system"); #endif - mCurrentBand.GetAvailableSpace(mY - mBorderPadding.top, mAvailSpaceRect); + mCurrentBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d} count=%d", @@ -379,7 +442,7 @@ nsBlockReflowState::GetAvailableSpace() mAvailSpaceRect.width, mAvailSpaceRect.height, mCurrentBand.GetTrapezoidCount())); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n", mAvailSpaceRect.x, mAvailSpaceRect.y, @@ -581,22 +644,7 @@ ListTextRuns(FILE* out, PRInt32 aIndent, nsTextRun* aRuns) NS_METHOD nsBlockFrame::List(FILE* out, PRInt32 aIndent) const { - PRInt32 i; - - nsAutoString tagString; - if (nsnull != mContent) { - nsIAtom* tag; - mContent->GetTag(tag); - if (tag != nsnull) { - tag->ToString(tagString); - NS_RELEASE(tag); - } - } - - // Indent - for (i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag + IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); @@ -613,7 +661,7 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const } // Output the rect and state - out << mRect; + fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } @@ -658,17 +706,17 @@ nsBlockFrame::List(FILE* out, PRInt32 aIndent) const // Output the text-runs if (nsnull != mTextRuns) { - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs("text-runs <\n", out); ListTextRuns(out, aIndent + 1, mTextRuns); - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); + IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; @@ -849,21 +897,29 @@ nsBlockFrame::ComputeCollapsedMargins(nsIPresContext& aPresContext, NS_IMETHODIMP nsBlockFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsBlockFrame::Reflow: maxSize=%d,%d reason=%d", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); +#if 0 +ListTag(stdout); printf(": reflow: maxSize=%d,%d computedSize=%d,%d\n", + aReflowState.availableWidth, + aReflowState.availableHeight, + aReflowState.computedWidth, + aReflowState.computedHeight); +#endif // Replace parent provided reflow state with our own significantly // more extensive version. nsLineLayout ll(aPresContext, aReflowState.spaceManager); nsLineLayout* lineLayout = ≪ - nsBlockReflowState state(aPresContext, aReflowState, aMetrics, lineLayout); + nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, + lineLayout); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } @@ -873,29 +929,31 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // the inline reflow engine so this setup is not wasted work: // because most content has compressed white-space in it, we will // use the inline reflow engine to get rid of it. - nsInlineReflow inlineReflow(*lineLayout, state, this, PR_TRUE); + nsInlineReflow inlineReflow(ll, aReflowState, this, PR_TRUE, + state.mComputeMaxElementSize); state.mInlineReflow = &inlineReflow; lineLayout->PushInline(&inlineReflow); // Compute the blocks minimum line-height the first time that its // needed (which is now). - nscoord minLineHeight = state.CalcLineHeight(aPresContext, this); + nscoord minLineHeight = nsHTMLReflowState::CalcLineHeight(aPresContext, this); inlineReflow.SetMinLineHeight(minLineHeight); nsresult rv = NS_OK; nsIFrame* target; - switch (state.reason) { + switch (aReflowState.reason) { case eReflowReason_Initial: DrainOverflowLines(); rv = PrepareInitialReflow(state); + ComputeTextRuns(aPresContext); mState &= ~NS_FRAME_FIRST_REFLOW; break; case eReflowReason_Incremental: - state.reflowCommand->GetTarget(target); + aReflowState.reflowCommand->GetTarget(target); if (this == target) { nsIReflowCommand::ReflowType type; - state.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); switch (type) { case nsIReflowCommand::FrameAppended: case nsIReflowCommand::FrameInserted: @@ -914,7 +972,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, } else { // Get next frame in reflow command chain - state.reflowCommand->GetNext(state.mNextRCFrame); + aReflowState.reflowCommand->GetNext(state.mNextRCFrame); + inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow ComputeTextRuns(aPresContext); @@ -933,14 +992,19 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, rv = ReflowDirtyLines(state); aStatus = state.mReflowStatus; if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - printf("XXX: block is not complete\n"); + if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) { + aStatus = NS_FRAME_COMPLETE; + } + else { + ListTag(stdout); printf(": block is not complete\n"); + } } // XXX get rid of this! BuildFloaterList(); // Compute our final size - ComputeFinalSize(state, aMetrics); + ComputeFinalSize(aReflowState, state, aMetrics); lineLayout->PopInline(); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, @@ -949,64 +1013,59 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, return rv; } -// XXX make this virtual -// XXX factor into its component pieces void -nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, - nsHTMLReflowMetrics& aMetrics) +nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, + nsBlockReflowState& aState, + nsHTMLReflowMetrics& aMetrics) { - // XXX handle floater problems this way... - PRBool isFixedWidth = aState.HaveFixedContentWidth(); - PRBool isFixedHeight = aState.HaveFixedContentHeight(); - -#if 0 - if (NS_BODY_SHRINK_WRAP & mFlags) { - isFixedWidth = PR_FALSE; - isFixedHeight = PR_FALSE; - } -#endif - // Compute final width - if (isFixedWidth) { + const nsMargin& borderPadding = aState.BorderPadding(); + if (!aState.mUnconstrainedWidth && aReflowState.HaveFixedContentWidth()) { // Use style defined width - aMetrics.width = aState.mBorderPadding.left + aState.computedWidth + - aState.mBorderPadding.right; + aMetrics.width = borderPadding.left + aReflowState.computedWidth + + borderPadding.right; } else { - nscoord computedWidth = aState.mKidXMost + aState.mBorderPadding.right; + nscoord computedWidth = aState.mKidXMost + borderPadding.right; PRBool compact = PR_FALSE; - if (NS_STYLE_DISPLAY_COMPACT == aState.mStyleDisplay->mDisplay) { + if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) { // If we are display: compact AND we have no lines or we have // exactly one line and that line is not a block line AND that // line doesn't end in a BR of any sort THEN we remain a compact // frame. if ((nsnull == mLines) || ((nsnull == mLines->mNext) && !mLines->IsBlock() && - (NS_STYLE_CLEAR_NONE == mLines->mBreakType) && - (computedWidth <= aState.mCompactMarginWidth))) { + (NS_STYLE_CLEAR_NONE == mLines->mBreakType) + /*XXX && (computedWidth <= aState.mCompactMarginWidth) */ + )) { compact = PR_TRUE; } } // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum available width. Note: + // contents or we fluff out to the maximum block width. Note: // We always shrink wrap when given an unconstrained width. if ((0 == (NS_BLOCK_SHRINK_WRAP & mFlags)) && !aState.mUnconstrainedWidth && !compact) { - // Fluff out to the max width if we aren't already that wide - if (computedWidth < aState.availableWidth) { - computedWidth = aState.availableWidth; - } + // Set our width to the max width if we aren't already that + // wide. Note that the max-width has nothing to do with our + // contents (CSS2 section XXX) + nscoord maxWidth = borderPadding.left + aState.mContentArea.width + + borderPadding.right; + computedWidth = maxWidth; } aMetrics.width = computedWidth; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.width > -200000) && (aMetrics.width < 200000), "oy"); +#endif // Compute final height - if (isFixedHeight) { + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { // Use style defined height - aMetrics.height = aState.mBorderPadding.top + aState.computedHeight + - aState.mBorderPadding.bottom; + aMetrics.height = borderPadding.top + aReflowState.computedHeight + + borderPadding.bottom; } else { // Shrink wrap our height around our contents. @@ -1016,9 +1075,12 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // XXX check for a fit aState.mY += aState.mPrevBottomMargin; } - aState.mY += aState.mBorderPadding.bottom; + aState.mY += borderPadding.bottom; aMetrics.height = aState.mY; } +#ifdef DEBUG_kipp + NS_ASSERTION((aMetrics.height > -200000) && (aMetrics.height < 200000), "oy"); +#endif // Return top and bottom margin information if (aState.mIsMarginRoot) { @@ -1034,17 +1096,13 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // sized then we collapse into nothingness. PRBool emptyFrame = PR_FALSE; // We need to check the specified width and see if it's 'auto' - const nsStylePosition* position; - aState.frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&) position); - PRIntn specifiedWidthUnit = position->mWidth.GetUnit(); + PRIntn specifiedWidthUnit = aReflowState.mStylePosition->mWidth.GetUnit(); if ((eStyleUnit_Auto == specifiedWidthUnit) && - (NS_AUTOHEIGHT == aState.computedHeight) && - ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top))) { + (NS_AUTOHEIGHT == aReflowState.computedHeight) && + ((0 == aState.mKidXMost - borderPadding.left) && + (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; - aState.mAscent = 0; - aState.mDescent = 0; emptyFrame = PR_TRUE; } @@ -1064,16 +1122,16 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, // width of the widest line plus the right border. Note that // aState.mKidXMost already has the left border factored into // it - maxWidth = aState.mKidXMost + aState.mBorderPadding.right; + maxWidth = aState.mKidXMost + borderPadding.right; } else { // Add in border and padding dimensions to already computed // max-element-size values. maxWidth = aState.mMaxElementSize.width + - aState.mBorderPadding.left + aState.mBorderPadding.right; + borderPadding.left + borderPadding.right; } maxHeight = aState.mMaxElementSize.height + - aState.mBorderPadding.top + aState.mBorderPadding.bottom; + borderPadding.top + borderPadding.bottom; } // Store away the final value @@ -1083,7 +1141,8 @@ nsBlockFrame::ComputeFinalSize(nsBlockReflowState& aState, ListTag(stdout); printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n", maxWidth, maxHeight, aMetrics.width, aMetrics.height, - aState.availableWidth, aState.availableHeight); + aState.mReflowState.availableWidth, + aState.mReflowState.availableHeight); #endif } @@ -1176,15 +1235,15 @@ printf(": => carried=%d,%d\n", aMetrics.carriedOutTopMargin, aMetrics.carriedOut nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mRunInFrame)) { + if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { #ifdef NOISY_RUNIN ListTag(stdout); printf(": run-in from: "); - aReflowState.mRunInFrame->ListTag(stdout); + aState.mReflowState.mRunInFrame->ListTag(stdout); printf("\n"); #endif // Take frames away from the run-in frame - TakeRunInFrames(aState.mRunInFrame); + TakeRunInFrames(aState.mReflowState.mRunInFrame); } PrepareResizeReflow(aState); @@ -1238,9 +1297,56 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) return NS_OK; } +void +nsBlockFrame::UpdateBulletPosition() +{ + const nsStyleList* styleList; + GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList); + if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { + if (HaveOutsideBullet()) { + // We now have an inside bullet, but used to have an outside + // bullet. Adjust the frame lists and mark the first line + // dirty. + if (nsnull != mLines) { + mBullet->SetNextSibling(mLines->mFirstChild); + mLines->mFirstChild = mBullet; + mLines->mChildCount++; + mLines->MarkDirty(); + } + } + mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } + else { + if (!HaveOutsideBullet()) { + // We now have an outside bullet, but used to have an inside + // bullet. Take the bullet frame out of the first lines frame + // list. + if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) { + nsIFrame* next; + mBullet->GetNextSibling(&next); + mBullet->SetNextSibling(nsnull); + if (--mLines->mChildCount == 0) { + nsLineBox* nextLine = mLines->mNext; + delete mLines; + mLines = nextLine; + if (nsnull != nextLine) { + nextLine->MarkDirty(); + } + } + else { + mLines->mFirstChild = next; + mLines->MarkDirty(); + } + } + } + mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; + } +} + nsresult nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) { + UpdateBulletPosition(); // XXX temporary return PrepareResizeReflow(aState); } @@ -1294,6 +1400,9 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, // Recover xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } @@ -1303,8 +1412,12 @@ nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; const nsStyleSpacing* spacing; frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)spacing); + // XXX use a reflow-state to do the necessary computations for blocks +#if XXX_fix_me nsBlockReflowContext::ComputeMarginsFor(aState.mPresContext, frame, - spacing, aState, childMargins); + spacing, aState.mReflowState, + childMargins); +#endif } // Recompute running margin value (aState.mPrevBottomMargin). Also @@ -1372,7 +1485,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord impactY0 = aLine->mCombinedArea.y; nscoord impactY1 = aLine->mCombinedArea.YMost(); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("impactY0=%d impactY1=%d deltaY=%d\n", impactY0, impactY1, aDeltaY); @@ -1392,7 +1505,7 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, nscoord lineY1 = lineY0 + next->mBounds.height; if ((lineY0 < impactY1) && (impactY0 < lineY1)) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p setting dirty\n", next); } @@ -1417,9 +1530,9 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) aState.mLineLayout->SetReflowTextRuns(mTextRuns); #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { nsIReflowCommand::ReflowType type; - aState.reflowCommand->GetType(type); + aState.mReflowState.reflowCommand->GetType(type); IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": incrementally reflowing dirty lines: type=%s(%d)\n", @@ -1434,11 +1547,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) nscoord deltaY = 0; while (nsnull != line) { #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d dirty=%s oldBounds=%d,%d,%d,%d deltaY=%d\n", line, aState.mY, line->IsDirty() ? "yes" : "no", - line->mBounds, deltaY); + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); gNoiseIndent++; } #endif @@ -1479,11 +1594,14 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) RecoverStateFrom(aState, line, deltaY); } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); printf("line=%p mY=%d newBounds=%d,%d,%d,%d deltaY=%d\n", - line, aState.mY, line->mBounds, deltaY); + line, aState.mY, + line->mBounds.x, line->mBounds.y, + line->mBounds.width, line->mBounds.height, + deltaY); } #endif @@ -1560,12 +1678,12 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) } #ifdef NOISY_INCREMENTAL_REFLOW - if (aState.reason == eReflowReason_Incremental) { + if (aState.mReflowState.reason == eReflowReason_Incremental) { gNoiseIndent--; IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": done reflowing dirty lines (status=%x, mLimitToOneLine=%d)\n", - aState.mReflowStatus, aState.mLimitToOneLine); + printf(": done reflowing dirty lines (status=%x)\n", + aState.mReflowStatus); } #endif @@ -1650,13 +1768,16 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // When reflowing a block frame we always get the available space aState.GetAvailableSpace(); +#if XXX_dead_code if ((nsnull != aState.lineLayout) && (0 != aState.lineLayout->GetPlacedFrames())) { // Blocks are not allowed on the same line as anything else aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE(); *aKeepReflowGoing = PR_FALSE; } - else { + else +#endif + { // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1674,7 +1795,8 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Setup initial coordinate system for reflowing the inline frames // into. - x = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + const nsMargin& borderPadding = aState.BorderPadding(); + x = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; if (aState.mUnconstrainedHeight) { @@ -2068,9 +2190,9 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) #ifdef NOISY_RUNIN ListTag(stdout); printf(": frame: "); - aFrame->ListTag(stdout); + nsFrame::ListTag(stdout, aFrame); printf(" followed by: "); - nextFrame->ListTag(stdout); + nsFrame::ListTag(stdout, nextFrame); printf("\n"); #endif followingBlockFrame = (nsBlockFrame*) nextFrame; @@ -2186,7 +2308,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine - nsBlockFrame* runInToFrame; +//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2194,6 +2316,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); switch (display->mDisplay) { +#if XXX_runin case NS_STYLE_DISPLAY_RUN_IN: #ifdef NOISY_RUNIN ListTag(stdout); @@ -2223,6 +2346,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } break; +#endif case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); @@ -2233,7 +2357,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = compactWithFrame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&) spacing); if (NS_SUCCEEDED(rv) && (nsnull != spacing)) { - nsHTMLReflowState::ComputeMarginFor(compactWithFrame, &aState, + nsHTMLReflowState::ComputeMarginFor(compactWithFrame, + &aState.mReflowState, margin); compactMarginWidth = margin.left; } @@ -2242,8 +2367,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, break; } - nsBlockReflowContext brc(aState.mPresContext, *aState.mLineLayout, aState); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, + aState.mComputeMaxElementSize); brc.SetCompactMarginWidth(compactMarginWidth); + brc.SetNextRCFrame(aState.mNextRCFrame); // Clear floaters before the block if the clear style is not none aLine->mBreakType = display->mBreakType; @@ -2260,12 +2387,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } +#if XXX_runin // Set run-in frame if this is the run-in-to frame. That way the // target block frame knows to pick up the children from the run-in // frame. if (frame == aState.mRunInToFrame) { brc.SetRunInFrame(aState.mRunInFrame); } +#endif // Compute the available space for the block nscoord availHeight = aState.mUnconstrainedHeight @@ -2277,6 +2406,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // then we get it an available space that is *NOT* affected by // floaters. Otherwise we position the block outside of the // floaters. + const nsMargin& borderPadding = aState.BorderPadding(); nscoord availX, availWidth; nsSplittableType splitType; switch (display->mDisplay) { @@ -2286,7 +2416,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, case NS_STYLE_DISPLAY_LIST_ITEM: if (NS_SUCCEEDED(frame->IsSplittable(splitType)) && (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == splitType)) { - availX = aState.mBorderPadding.left; + availX = borderPadding.left; availWidth = aState.mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : aState.mContentArea.width; @@ -2296,7 +2426,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // FALLTHROUGH default: - availX = aState.mAvailSpaceRect.x + aState.mBorderPadding.left; + availX = aState.mAvailSpaceRect.x + borderPadding.left; availWidth = aState.mAvailSpaceRect.width; break; } @@ -2451,7 +2581,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, rv = frame->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&) font); if (NS_SUCCEEDED(rv) && (nsnull != font)) { - nsIRenderingContext& rc = *aState.rendContext; + nsIRenderingContext& rc = *aState.mReflowState.rendContext; rc.SetFont(font->mFont); nsIFontMetrics* fm; rv = rc.GetFontMetrics(fm); @@ -2465,7 +2595,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, nsRect bbox; mBullet->GetRect(bbox); nscoord topMargin = applyTopMargin ? brc.GetCollapsedTopMargin() : 0; - bbox.y = aState.mBorderPadding.top + ascent - metrics.ascent + + bbox.y = borderPadding.top + ascent - metrics.ascent + topMargin; mBullet->SetRect(bbox); } @@ -2789,18 +2919,26 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, ir.AddFrame(mBullet, metrics); addedBullet = PR_TRUE; } - ir.VerticalAlignFrames(aLine->mBounds, aState.mAscent, aState.mDescent); + nscoord a, d; + ir.VerticalAlignFrames(aLine->mBounds, a, d); if (addedBullet) { ir.RemoveFrame(mBullet); } +#ifdef DEBUG_kipp + NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); +#endif // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). +#if XXX_fix_me PRBool allowJustify = PR_TRUE; if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) { allowJustify = ShouldJustifyLine(aState, aLine); } +#else + PRBool allowJustify = PR_FALSE; +#endif ir.TrimTrailingWhiteSpace(aLine->mBounds); ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); ir.RelativePositionFrames(aLine->mCombinedArea); @@ -2975,6 +3113,9 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, // Update xmost nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { +#ifdef DEBUG_kipp + NS_ASSERTION((xmost > -200000) && (xmost < 200000), "oy"); +#endif aState.mKidXMost = xmost; } } @@ -3906,17 +4047,14 @@ nsBlockFrame::ReflowFloater(nsIPresContext& aPresContext, { // If either dimension is constrained then get the border and // padding values in advance. - nsMargin bp(0, 0, 0, 0); - if (aFloaterReflowState.HaveFixedContentWidth() || - aFloaterReflowState.HaveFixedContentHeight()) { - nsHTMLReflowState::ComputeBorderPaddingFor(aFloaterFrame, &aState, bp); - } + const nsMargin& bp = aFloaterReflowState.mComputedBorderPadding; // Compute the available width for the floater if (aFloaterReflowState.HaveFixedContentWidth()) { // When the floater has a contrained width, give it just enough // space for its styled width plus its borders and paddings. - aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + bp.left + bp.right; + aFloaterReflowState.availableWidth = aFloaterReflowState.computedWidth + + bp.left + bp.right; } else { // CSS2 section 10.3.5: Floating non-replaced elements with an @@ -3986,13 +4124,15 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Reflow the floater nsIFrame* floater = aPlaceholder->GetAnchoredItem(); nsSize kidAvailSize(0, 0); - nsHTMLReflowState reflowState(mPresContext, floater, *this, kidAvailSize); + nsHTMLReflowState reflowState(mPresContext, mReflowState, floater, + kidAvailSize); reflowState.lineLayout = nsnull; - if ((nsnull == reflowCommand) || (floater != mNextRCFrame)) { + if ((nsnull == mReflowState.reflowCommand) || (floater != mNextRCFrame)) { // Stub out reflowCommand and repair reason in the reflowState // when incremental reflow doesn't apply to the floater. reflowState.reflowCommand = nsnull; - reflowState.reason = ((reason == eReflowReason_Initial) || aInitialReflow) + reflowState.reason = + ((mReflowState.reason == eReflowReason_Initial) || aInitialReflow) ? eReflowReason_Initial : eReflowReason_Resize; } @@ -4026,7 +4166,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + mBorderPadding.left, + mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, mY, mAvailSpaceRect.width, mAvailSpaceRect.height, @@ -4125,7 +4265,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, nsRect region; floater->GetRect(region); nsMargin floaterMargin; - ComputeMarginFor(floater, this, floaterMargin); + // XXX sometimes when we reflow the floater we already have this value... + nsHTMLReflowState::ComputeMarginFor(floater, &mReflowState, floaterMargin); // Adjust the floater size by its margin. That's the area that will // impact the space manager. @@ -4180,7 +4321,8 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, region.x = mAvailSpaceRect.x; } } - region.y = mY - mBorderPadding.top; + const nsMargin& borderPadding = BorderPadding(); + region.y = mY - borderPadding.top; if (region.y < 0) { // CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not // be higher than the top of its containing block. @@ -4196,14 +4338,14 @@ nsBlockReflowState::PlaceFloater(nsPlaceholderFrame* aPlaceholder, // Set the origin of the floater frame, in frame coordinates. These // coordinates are not relative to the spacemanager // translation, therefore we have to factor in our border/padding. - floater->MoveTo(mBorderPadding.left + floaterMargin.left + region.x, - mBorderPadding.top + floaterMargin.top + region.y); + floater->MoveTo(borderPadding.left + floaterMargin.left + region.x, + borderPadding.top + floaterMargin.top + region.y); // Now restore mY mY = saveY; #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsRect r; floater->GetRect(r); nsFrame::IndentBy(stdout, gNoiseIndent); @@ -4256,23 +4398,22 @@ void nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType) { #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); printf("clear floaters: in: mY=%d aY=%d(%d)\n", - mY, aY, aY - mBorderPadding.top); + mY, aY, aY - BorderPadding().top); } #endif - nscoord newY = mCurrentBand.ClearFloaters(aY - mBorderPadding.top, - aBreakType); - mY = newY + mBorderPadding.top; + const nsMargin& bp = BorderPadding(); + nscoord newY = mCurrentBand.ClearFloaters(aY - bp.top, aBreakType); + mY = newY + bp.top; GetAvailableSpace(); #ifdef NOISY_INCREMENTAL_REFLOW - if (reason == eReflowReason_Incremental) { + if (mReflowState.reason == eReflowReason_Incremental) { nsFrame::IndentBy(stdout, gNoiseIndent); - printf("clear floaters: out: mY=%d(%d)\n", - mY, mY - mBorderPadding.top); + printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top); } #endif } @@ -4514,6 +4655,7 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, if (NS_FAILED(rv)) { return rv; } + RenumberLists(); // Create list bullet if this is a list-item. Note that this is done // here so that RenumberLists will work (it needs the bullets to @@ -4637,8 +4779,9 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, nsSize availSize; availSize.width = NS_UNCONSTRAINEDSIZE; availSize.height = NS_UNCONSTRAINEDSIZE; - nsHTMLReflowState reflowState(aState.mPresContext, mBullet, aState, - availSize, aState.mLineLayout); + nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, + mBullet, availSize); + reflowState.lineLayout = aState.mLineLayout; nsIHTMLReflow* htmlReflow; nsresult rv = mBullet->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); if (NS_SUCCEEDED(rv)) { @@ -4650,13 +4793,12 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // Place the bullet now; use its right margin to distance it // from the rest of the frames in the line - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(mBullet, &aState, margin); - nscoord x = aState.mBorderPadding.left - margin.right - aMetrics.width; + const nsMargin& bp = aState.BorderPadding(); + nscoord x = bp.left - reflowState.computedMargin.right - aMetrics.width; // Approximate the bullets position; vertical alignment will provide // the final vertical location. - nscoord y = aState.mBorderPadding.top; + nscoord y = bp.top; mBullet->SetRect(nsRect(x, y, aMetrics.width, aMetrics.height)); }