diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index dd9ca8b5067..0ea613b8178 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -277,8 +277,6 @@ protected: nsLineBox* aLine, nscoord aDeltaY); - void TakeRunInFrames(nsBlockFrame* aRunInFrame); - nsresult ComputeTextRuns(nsIPresContext& aPresContext); void BuildFloaterList(); diff --git a/mozilla/layout/generic/nsBlockReflowContext.cpp b/mozilla/layout/generic/nsBlockReflowContext.cpp index 5ccb35f8d69..ac11c762211 100644 --- a/mozilla/layout/generic/nsBlockReflowContext.cpp +++ b/mozilla/layout/generic/nsBlockReflowContext.cpp @@ -38,7 +38,6 @@ nsBlockReflowContext::nsBlockReflowContext(nsIPresContext& aPresContext, mOuterReflowState(aParentRS), mMetrics(aComputeMaxElementSize ? &mMaxElementSize : nsnull) { - mRunInFrame = nsnull; mCompactMarginWidth = 0; mStyleSpacing = nsnull; } @@ -102,7 +101,6 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame, availSpace, reason); aComputedOffsets = reflowState.computedOffsets; reflowState.lineLayout = nsnull; - reflowState.mRunInFrame = mRunInFrame; reflowState.mCompactMarginWidth = mCompactMarginWidth; if (!aIsAdjacentWithTop) { reflowState.isTopOfPage = PR_FALSE; // make sure this is cleared @@ -312,6 +310,8 @@ nsBlockReflowContext::PlaceBlock(PRBool aForceFit, mFrame->SetRect(r); aInFlowBounds = r; aCombinedRect = mMetrics.mCombinedArea; + mTopMargin = 0; + mBottomMargin = 0; fits = PR_TRUE; } else { diff --git a/mozilla/layout/generic/nsBlockReflowContext.h b/mozilla/layout/generic/nsBlockReflowContext.h index b3104e91802..f8835ddc398 100644 --- a/mozilla/layout/generic/nsBlockReflowContext.h +++ b/mozilla/layout/generic/nsBlockReflowContext.h @@ -40,10 +40,6 @@ public: PRBool aComputeMaxElementSize); ~nsBlockReflowContext() { } - void SetRunInFrame(nsBlockFrame* aRunInFrame) { - mRunInFrame = aRunInFrame; - } - void SetCompactMarginWidth(nscoord aCompactMarginWidth) { mCompactMarginWidth = aCompactMarginWidth; } @@ -132,7 +128,6 @@ protected: const nsHTMLReflowState& mOuterReflowState; nsIFrame* mFrame; - nsBlockFrame* mRunInFrame; nscoord mCompactMarginWidth; nsRect mSpace; nsIFrame* mNextRCFrame; diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/generic/nsBulletFrame.cpp b/mozilla/layout/generic/nsBulletFrame.cpp index 6556ddb693a..23e1ae86183 100644 --- a/mozilla/layout/generic/nsBulletFrame.cpp +++ b/mozilla/layout/generic/nsBulletFrame.cpp @@ -71,6 +71,7 @@ nsBulletFrame::Paint(nsIPresContext& aCX, if (disp->mVisible) { const nsStyleList* myList = (const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List); + PRUint8 listStyleType = myList->mListStyleType; if (myList->mListStyleImage.Length() > 0) { nsIImage* image = mImageLoader.GetImage(); @@ -81,11 +82,14 @@ nsBulletFrame::Paint(nsIPresContext& aCX, } } else { - nsRect innerArea(mPadding.left, mPadding.top, - mRect.width - (mPadding.left + mPadding.right), - mRect.height - (mPadding.top + mPadding.bottom)); - aRenderingContext.DrawImage(image, innerArea); - return NS_OK; + if (!mImageLoader.GetLoadImageFailed()) { + nsRect innerArea(mPadding.left, mPadding.top, + mRect.width - (mPadding.left + mPadding.right), + mRect.height - (mPadding.top + mPadding.bottom)); + aRenderingContext.DrawImage(image, innerArea); + return NS_OK; + } + listStyleType = NS_STYLE_LIST_STYLE_DISC; } } @@ -98,7 +102,7 @@ nsBulletFrame::Paint(nsIPresContext& aCX, aRenderingContext.SetColor(myColor->mColor); nsAutoString text; - switch (myList->mListStyleType) { + switch (listStyleType) { case NS_STYLE_LIST_STYLE_NONE: break; diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 346e7a44e47..c539e0fa6f4 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -1048,17 +1048,6 @@ nsFrame::MoveInSpaceManager(nsIPresContext& aPresContext, return NS_OK; } -NS_IMETHODIMP -nsFrame::VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedRect) -{ - aCombinedRect = mRect; - return NS_OK; -} - NS_IMETHODIMP nsFrame::ContentChanged(nsIPresContext* aPresContext, nsIContent* aChild, diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index e2e93645efb..7bf0d2a163a 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -234,11 +234,6 @@ public: NS_IMETHOD MoveInSpaceManager(nsIPresContext& aPresContext, nsISpaceManager* aSpaceManager, nscoord aDeltaX, nscoord aDeltaY); - NS_IMETHOD VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedRect); // Selection Methods // XXX Doc me... (in nsIFrame.h puhleeze) diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index 25e4695569b..66e78923f61 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -115,7 +115,7 @@ nsHTMLContainerFrame::CreateNextInFlow(nsIPresContext& aPresContext, nextInFlow->SetNextSibling(nextFrame); NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES, - ("nsInlineReflow::MaybeCreateNextInFlow: frame=%p nextInFlow=%p", + ("nsHTMLContainerFrame::MaybeCreateNextInFlow: frame=%p nextInFlow=%p", aFrame, nextInFlow)); aNextInFlowResult = nextInFlow; diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 66732bed96f..568cf6534a7 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -126,7 +126,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext& aPresContext, void nsHTMLReflowState::Init(nsIPresContext& aPresContext) { - mRunInFrame = nsnull; mCompactMarginWidth = 0; mAlignCharOffset = 0; mUseAlignCharOffset = 0; @@ -1119,25 +1118,23 @@ nsHTMLReflowState::CalcLineHeight(nsIPresContext& aPresContext, sc->GetStyleData(eStyleStruct_Text); if (nsnull != text) { nsStyleUnit unit = text->mLineHeight.GetUnit(); - if (eStyleUnit_Enumerated == unit) { - // Normal value; we use 1.0 for normal - // XXX could come from somewhere else + if (eStyleUnit_Normal == unit) { + // Normal value; we use a factor of 1.0 for normal + lineHeight = elementFont->mFont.size; #ifdef NOISY_VERTICAL_ALIGN - printf(" line-height: normal\n"); + printf(" line-height: normal result=%d\n", lineHeight); #endif break; } else if (eStyleUnit_Factor == unit) { - if (nsnull != elementFont) { - // CSS2 spec says that the number is inherited, not the - // computed value. Therefore use the font size of the - // element times the inherited number. - nscoord size = elementFont->mFont.size; - lineHeight = nscoord(size * text->mLineHeight.GetFactorValue()); + // CSS2 spec says that the number is inherited, not the + // computed value. Therefore use the font size of the + // element times the inherited number. + nscoord size = elementFont->mFont.size; + lineHeight = nscoord(size * text->mLineHeight.GetFactorValue()); #ifdef NOISY_VERTICAL_ALIGN - printf(" line-height: factor=%g result=%d\n", - text->mLineHeight.GetFactorValue(), lineHeight); + printf(" line-height: factor=%g result=%d\n", + text->mLineHeight.GetFactorValue(), lineHeight); #endif - } break; } else if (eStyleUnit_Coord == unit) { diff --git a/mozilla/layout/generic/nsImageMap.cpp b/mozilla/layout/generic/nsImageMap.cpp index 4f794005e40..31850c74fd0 100644 --- a/mozilla/layout/generic/nsImageMap.cpp +++ b/mozilla/layout/generic/nsImageMap.cpp @@ -77,8 +77,8 @@ public: nsString mAltText; nscoord* mCoords; PRInt32 mNumCoords; - PRBool mHasURL; PRBool mSuppressFeedback; + PRBool mHasURL; }; Area::Area(const nsString& aBaseURL, const nsString& aHREF, @@ -753,7 +753,7 @@ nsImageMap::UpdateAreas() // Get rid of old area data FreeAreas(); - nsresult rv; + nsresult rv = NS_OK; nsIContent* child; PRInt32 i, n; PRBool containsBlock = PR_FALSE, containsArea = PR_FALSE; diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index aa3fb212cc7..67e433c8bd6 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -20,7 +20,6 @@ #include "nsFrameList.h" #include "nsBlockReflowContext.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" @@ -28,6 +27,8 @@ #include "nsIStyleContext.h" #include "nsIPresShell.h" #include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsIFontMetrics.h" // XXX TODO: // append/insert/remove floater testing @@ -35,7 +36,7 @@ // Theory of operation: // XXX write this -#ifdef NS_DEBUG +#ifdef DEBUG #undef NOISY_ANON_BLOCK #else #undef NOISY_ANON_BLOCK @@ -89,17 +90,11 @@ public: nsIRenderingContext& aRC, nscoord& aDeltaWidth); #endif - NS_IMETHOD VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aParentReflowState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedArea); protected: // Additional reflow state used during our reflow methods struct InlineReflowState { nsIFrame* mNextRCFrame; - nsInlineReflow* mInlineReflow; nsIFrame* mPrevFrame; nsInlineFrame* mNextInFlow; }; @@ -1184,13 +1179,15 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { + if (nsnull == aReflowState.lineLayout) { + return NS_ERROR_INVALID_ARG; + } DrainOverflow(); // Set our own reflow state (additional state above and beyond // aReflowState) InlineReflowState irs; irs.mPrevFrame = nsnull; - irs.mInlineReflow = nsnull; irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; if (eReflowReason_Incremental == aReflowState.reason) { // Peel off the next frame in the path if this is an incremental @@ -1228,8 +1225,7 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, } if (HaveAnonymousBlock()) { - if ((nsnull != aReflowState.lineLayout) && - (0 != aReflowState.lineLayout->GetPlacedFrames())) { + if (!aReflowState.lineLayout->LineIsEmpty()) { // This inline frame cannot be placed on the current line // because there already is an inline frame on this line (and we // contain an anonymous block). @@ -1239,30 +1235,27 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, else { rv = ReflowBlockFrame(aPresContext, aReflowState, irs, aMetrics, aStatus); + + // If the combined area of our children exceeds our bounding box + // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear + // it. + if ((aMetrics.mCombinedArea.x < 0) || + (aMetrics.mCombinedArea.y < 0) || + (aMetrics.mCombinedArea.XMost() > aMetrics.width) || + (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } + else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } } } else { - if (nsnull != aReflowState.lineLayout) { - rv = ReflowInlineFrames(aPresContext, aReflowState, irs, - aMetrics, aStatus); - } - else { - rv = NS_ERROR_NULL_POINTER; - } - } - - if (NS_SUCCEEDED(rv)) { - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } + rv = ReflowInlineFrames(aPresContext, aReflowState, irs, + aMetrics, aStatus); + // Note: when we are reflowing inline frames the line layout code + // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for + // us. } return rv; @@ -1288,114 +1281,6 @@ nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) return NS_OK; } -// Perform pass2 vertical alignment on top/bottom aligned child frames -// XXX relative positioning will need to be done *after* this -NS_IMETHODIMP -nsInlineFrame::VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aParentReflowState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedArea) -{ - if (HaveAnonymousBlock()) { - // This should be impossible - when we have an inline frame and it - // contains an anonymous block, none of the blocks children or the - // block itself will trigger a pass2 valign at this level. - NS_NOTREACHED("can't get here"); - aCombinedArea = mRect; - return NS_OK; - } - - // topEdge is the y coordinate of the line's top, relative to this - // frame (== in this frames local coordinate system). - nscoord topEdge = -aDistanceFromTopEdge; - - nsRect bbox, childCombinedArea; - nscoord x0 = 0; - nscoord y0 = 0; - nscoord x1 = mRect.width; - nscoord y1 = mRect.height; - nsIFrame* frame = mFrames.FirstChild(); - while (nsnull != frame) { - const nsStyleText* textStyle; - frame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)textStyle); - nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit(); - frame->GetRect(bbox); - - if (eStyleUnit_Enumerated == verticalAlignUnit) { - PRUint8 verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue(); - if (NS_STYLE_VERTICAL_ALIGN_TOP == verticalAlignEnum) { - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(frame, &aParentReflowState, - margin); - nsCSSFrameType frameType = - nsHTMLReflowState::DetermineFrameType(frame); - bbox.y = topEdge + margin.top; - if (NS_CSS_FRAME_TYPE_INLINE == frameType) { - nsMargin bp; - nsHTMLReflowState::ComputeBorderPaddingFor(frame, - &aParentReflowState, bp); - bbox.y -= bp.top; - } - frame->SetRect(bbox); - } - else if (NS_STYLE_VERTICAL_ALIGN_BOTTOM == verticalAlignEnum) { - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(frame, &aParentReflowState, - margin); - nsCSSFrameType frameType = - nsHTMLReflowState::DetermineFrameType(frame); - bbox.y = topEdge + aLineHeight - bbox.height - margin.bottom; - if (NS_CSS_FRAME_TYPE_INLINE == frameType) { - nsMargin bp; - nsHTMLReflowState::ComputeBorderPaddingFor(frame, - &aParentReflowState, bp); - bbox.y += bp.bottom; - } - frame->SetRect(bbox); - } - } - - // Perform pass2 vertical alignment for top/bottom aligned - // frames that are not our direct descendants. - nsIHTMLReflow* ihr; - nsresult rv = frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr); - if (NS_SUCCEEDED(rv)) { - nsSize availSize(0, 0); - // XXX whacky: we should be passing in the childs reflow state, right? - nsHTMLReflowState ourReflowState(aPresContext, aParentReflowState, - this, availSize); - nscoord distanceFromTopEdge = bbox.y - topEdge; - ihr->VerticalAlignFrames(aPresContext, ourReflowState, aLineHeight, - distanceFromTopEdge, childCombinedArea); - nscoord x = childCombinedArea.x; - if (x < x0) x0 = x; - nscoord y = childCombinedArea.y; - if (y < y0) y0 = y; - nscoord xmost = childCombinedArea.XMost(); - if (xmost > x1) x1 = xmost; - nscoord ymost = childCombinedArea.YMost(); - if (ymost > y1) y1 = ymost; - } - - frame->GetNextSibling(&frame); - } - - aCombinedArea.x = mRect.x + x0; - aCombinedArea.y = mRect.y + y0; - aCombinedArea.width = x1 - x0; - aCombinedArea.height = y1 - y0; - - // Update our outside-children flag bit - if ((x0 < 0) || (y0 < 0) || (x1 > mRect.width) || (y1 > mRect.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - return NS_OK; -} - void nsInlineFrame::DrainOverflow() { @@ -1427,35 +1312,19 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext& aPresContext, nsresult rv = NS_OK; aStatus = NS_FRAME_COMPLETE; - nsInlineReflow ir(*aReflowState.lineLayout, aReflowState, this, PR_FALSE, - nsnull != aMetrics.maxElementSize); - irs.mInlineReflow = &ir; - ir.SetNextRCFrame(irs.mNextRCFrame); - aReflowState.lineLayout->PushInline(&ir); - - // Compute available area - nscoord x = aReflowState.mComputedBorderPadding.left; + nsLineLayout* lineLayout = aReflowState.lineLayout; + nscoord leftEdge = 0; + if (nsnull == mPrevInFlow) { + leftEdge = aReflowState.mComputedBorderPadding.left; + } nscoord availableWidth = aReflowState.availableWidth; if (NS_UNCONSTRAINEDSIZE != availableWidth) { - if (nsnull != mPrevInFlow) { - x = 0; - availableWidth -= aReflowState.mComputedBorderPadding.right + - aReflowState.computedMargin.right; - } - else { - availableWidth -= aReflowState.mComputedBorderPadding.left + - aReflowState.computedMargin.left + - aReflowState.mComputedBorderPadding.right + - aReflowState.computedMargin.right; - } + // Subtract off left and right border+padding from availableWidth + availableWidth -= leftEdge; + availableWidth -= aReflowState.mComputedBorderPadding.right; } - nscoord y = aReflowState.mComputedBorderPadding.top; - nscoord availableHeight = aReflowState.availableHeight; - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) { - availableHeight -= aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.right; - } - ir.Init(x, y, availableWidth, availableHeight); + lineLayout->BeginSpan(this, &aReflowState, + leftEdge, leftEdge + availableWidth); // First reflow our current children nsIFrame* frame = mFrames.FirstChild(); @@ -1489,37 +1358,99 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext& aPresContext, irs.mPrevFrame = frame; } } - - // Compute final metrics - if (NS_SUCCEEDED(rv)) { -#ifdef NS_DEBUG - if (NS_FRAME_COMPLETE == aStatus) { - // We can't be complete AND have overflow frames! - NS_ASSERTION(mOverflowFrames.IsEmpty(), "whoops"); - } +#ifdef DEBUG + if (NS_FRAME_COMPLETE == aStatus) { + // We can't be complete AND have overflow frames! + NS_ASSERTION(mOverflowFrames.IsEmpty(), "whoops"); + } #endif - nsInlineReflow* ir = irs.mInlineReflow; - nsRect bbox; - ir->VerticalAlignFrames(bbox, aMetrics.ascent, aMetrics.descent); - ir->RelativePositionFrames(aMetrics.mCombinedArea); - aMetrics.width = bbox.XMost(); + + // If after reflowing our children they take up no area then make + // sure that we don't either. + nsSize size; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + if ((0 == size.height) && (0 == size.width)) { + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = 0; + aMetrics.maxElementSize->height = 0; + } + } + else { + // Compute final width + aMetrics.width = size.width; + if (nsnull == mPrevInFlow) { + aMetrics.width += aReflowState.mComputedBorderPadding.left; + } if (NS_FRAME_IS_COMPLETE(aStatus)) { aMetrics.width += aReflowState.mComputedBorderPadding.right; } - aMetrics.height = bbox.height + aReflowState.mComputedBorderPadding.top + + + // Compute final height. The height of our box is the sum of our + // font size plus the top and bottom border and padding. The height + // of children do not affect our height. + // + // Note 2: we use the actual font height for sizing our selves instead + // of the computed font height. On systems where they disagree the + // actual font height is more appropriate. + const nsStyleFont* font; + GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); + aReflowState.rendContext->SetFont(font->mFont); + nsIFontMetrics* fm; + aReflowState.rendContext->GetFontMetrics(fm); + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom; -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": metrics=%d,%d ascent=%d descent=%d\n", - aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); -#endif - aMetrics.mCarriedOutTopMargin = 0; - aMetrics.mCarriedOutBottomMargin = 0; - if (nsnull != aMetrics.maxElementSize) { - *aMetrics.maxElementSize = ir->GetMaxElementSize(); + +#if defined(DEBUG) && defined(XP_UNIX) + static PRBool useComputedHeight = PR_FALSE; + static PRBool firstTime = 1; + if (firstTime) { + if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { + useComputedHeight = PR_TRUE; + } } + if (useComputedHeight) { + // Special debug code that violates the above CSS2 spec + // clarification. Why? So that we can predictably compute the values + // for testing layout. + nscoord computedHeight = aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom + + font->mFont.size; + if (computedHeight != aMetrics.height) { + if (0 == (mState & 0x80000000)) { + nsFrame::ListTag(stdout, this); + printf(": using computedHeight %d instead of actual height %d\n", + computedHeight, aMetrics.height); + mState |= 0x80000000; + } + aMetrics.height = computedHeight; + } + } +#endif + + NS_RELEASE(fm); } - aReflowState.lineLayout->PopInline(); + + // For now our combined area is zero. The real value will be + // computed during vertical alignment of the line we are on. + aMetrics.mCombinedArea.x = 0; + aMetrics.mCombinedArea.y = 0; + aMetrics.mCombinedArea.width = aMetrics.width; + aMetrics.mCombinedArea.height = aMetrics.height; + +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": metrics=%d,%d ascent=%d descent=%d\n", + aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); +#endif return rv; } @@ -1543,8 +1474,8 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext& aPresContext, return NS_OK; } - nsInlineReflow* ir = irs.mInlineReflow; - nsresult rv = ir->ReflowFrame(aFrame, PR_FALSE/* XXX */, aStatus); + nsLineLayout* lineLayout = aReflowState.lineLayout; + nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); if (NS_FAILED(rv)) { return rv; } @@ -1656,7 +1587,7 @@ nsInlineFrame::PushFrames(nsIFrame* aFromChild, nsIFrame* aPrevSibling) { NS_PRECONDITION(nsnull != aFromChild, "null pointer"); NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); -#ifdef NS_DEBUG +#ifdef DEBUG nsIFrame* prevNextSibling; aPrevSibling->GetNextSibling(&prevNextSibling); NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); diff --git a/mozilla/layout/generic/nsLineBox.cpp b/mozilla/layout/generic/nsLineBox.cpp index 251458a8c4d..004c3820b71 100644 --- a/mozilla/layout/generic/nsLineBox.cpp +++ b/mozilla/layout/generic/nsLineBox.cpp @@ -46,16 +46,19 @@ nsLineBox::~nsLineBox() static void ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters) { + nsAutoString frameName; PRInt32 j, i, n = aFloaters->Count(); for (i = 0; i < n; i++) { for (j = aIndent; --j >= 0; ) fputs(" ", out); nsPlaceholderFrame* ph = (nsPlaceholderFrame*) aFloaters->ElementAt(i); if (nsnull != ph) { - fprintf(out, "placeholder@%p\n", ph); + fprintf(out, "placeholder@%p ", ph); nsIFrame* frame = ph->GetAnchoredItem(); if (nsnull != frame) { - frame->List(out, aIndent + 1); + frame->GetFrameName(frameName); + fputs(frameName, out); } + fprintf(out, "\n"); } } } @@ -277,14 +280,7 @@ nsLineBox::UnplaceFloaters(nsISpaceManager* aSpaceManager) PRBool nsLineBox::CheckIsBlock() const { - nsIFrame* frame = mFirstChild; - const nsStyleDisplay* display; - frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(display, position); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(mFirstChild); return isBlock == IsBlock(); } #endif diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 9a7cb8d366f..274f605c6b8 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -16,12 +16,38 @@ * Corporation. Portions created by Netscape are Copyright (C) 1998 * Netscape Communications Corporation. All Rights Reserved. */ +#include "nsCOMPtr.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsStyleConsts.h" +#include "nsHTMLContainerFrame.h" +#include "nsHTMLIIDs.h" +#include "nsISpaceManager.h" #include "nsIStyleContext.h" #include "nsIPresContext.h" #include "nsIFontMetrics.h" +#include "nsIRenderingContext.h" + +#ifdef DEBUG +#undef NOISY_HORIZONTAL_ALIGN +#undef REALLY_NOISY_HORIZONTAL_ALIGN +#undef NOISY_VERTICAL_ALIGN +#undef REALLY_NOISY_VERTICAL_ALIGN +#undef NOISY_REFLOW +#undef REALLY_NOISY_REFLOW +#undef NOISY_PUSHING +#undef REALLY_NOISY_PUSHING +#define DEBUG_ADD_TEXT +#else +#undef NOISY_HORIZONTAL_ALIGN +#undef REALLY_NOISY_HORIZONTAL_ALIGN +#undef NOISY_VERTICAL_ALIGN +#undef REALLY_NOISY_VERTICAL_ALIGN +#undef NOISY_REFLOW +#undef REALLY_NOISY_REFLOW +#undef NOISY_PUSHING +#undef REALLY_NOISY_PUSHING +#undef DEBUG_ADD_TEXT +#endif nsTextRun::nsTextRun() { @@ -44,96 +70,1716 @@ nsTextRun::List(FILE* out, PRInt32 aIndent) nsAutoString tmp; text->GetFrameName(tmp); fputs(tmp, out); - printf(" "); + printf("@%p ", text); } fputs(">\n", out); } //---------------------------------------------------------------------- +#define PLACED_LEFT 0x1 +#define PLACED_RIGHT 0x2 + +#define NUM_SPAN_DATA (sizeof(mSpanDataBuf) / sizeof(mSpanDataBuf[0])) +#define NUM_FRAME_DATA (sizeof(mFrameDataBuf) / sizeof(mFrameDataBuf[0])) + nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, - nsISpaceManager* aSpaceManager) - : mPresContext(aPresContext) + nsISpaceManager* aSpaceManager, + const nsHTMLReflowState* aOuterReflowState, + PRBool aComputeMaxElementSize) + : mPresContext(aPresContext), + mSpaceManager(aSpaceManager), + mBlockReflowState(aOuterReflowState), + mComputeMaxElementSize(aComputeMaxElementSize) { - mSpaceManager = aSpaceManager; - mListPositionOutside = PR_FALSE; + // Stash away some style data that we need + aOuterReflowState->frame->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) mStyleText); + mTextAlign = mStyleText->mTextAlign; + switch (mStyleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + mDirection = aOuterReflowState->mStyleDisplay->mDirection; + mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext, + aOuterReflowState->frame); + mBRFrame = nsnull; mLineNumber = 0; mColumn = 0; - mUnderstandsWhiteSpace = PR_FALSE; mEndsInWhiteSpace = PR_TRUE; + mUnderstandsWhiteSpace = PR_FALSE; + mFirstLetterStyleOK = PR_FALSE; + mIsTopOfPage = PR_FALSE; + mWasInWord = PR_FALSE; + mCanBreakBeforeFrame = PR_FALSE; + mUpdatedBand = PR_FALSE; + mPlacedFloaters = 0; + mTotalPlacedFrames = 0; + mTopEdge = mBottomEdge = 0; + mReflowTextRuns = nsnull; + mTextRun = nsnull; - mTextRuns = nsnull; - ResetTextRuns(); -} + // XXX Do this on demand to avoid extra setup time + // Place the baked-in per-frame-data on the frame free list + PerFrameData** pfdp = &mFrameFreeList; + PerFrameData* pfd = mFrameDataBuf; + PerFrameData* endpfd = pfd + NUM_FRAME_DATA; + while (pfd < endpfd) { +#ifdef DEBUG + nsCRT::memset(pfd, 0xEE, sizeof(*pfd)); +#endif + *pfdp = pfd; + pfdp = &pfd->mNext; + pfd++; + } + *pfdp = nsnull; -nsLineLayout::~nsLineLayout() -{ - nsTextRun::DeleteTextRuns(mTextRuns); -} + // XXX Do this on demand to avoid extra setup time + // Place the baked-in per-span-data on the span free list + PerSpanData** psdp = &mSpanFreeList; + PerSpanData* psd = mSpanDataBuf; + PerSpanData* endpsd = psd + NUM_SPAN_DATA; + while (psd < endpsd) { +#ifdef DEBUG + nsCRT::memset(psd, 0xEE, sizeof(*psd)); +#endif + *psdp = psd; + psdp = &psd->mNext; + psd++; + } + *psdp = nsnull; + + mCurrentSpan = mRootSpan = mLastSpan = nsnull; + mSpanDepth = 0; -void -nsLineLayout::ResetTextRuns() -{ - nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; mTextRunP = &mTextRuns; mNewTextRun = nsnull; } -nsTextRun* -nsLineLayout::TakeTextRuns() +nsLineLayout::nsLineLayout(nsIPresContext& aPresContext) + : mPresContext(aPresContext) { - nsTextRun* result = mTextRuns; mTextRuns = nsnull; - ResetTextRuns(); - return result; + mTextRunP = &mTextRuns; + mNewTextRun = nsnull; + mRootSpan = nsnull; + mSpanFreeList = nsnull; + mFrameFreeList = nsnull; +} + +nsLineLayout::~nsLineLayout() +{ + NS_ASSERTION(nsnull == mRootSpan, "bad line-layout user"); + nsTextRun::DeleteTextRuns(mTextRuns); + + // Free up all of the per-span-data items that were allocated on the heap + PerSpanData* psd = mSpanFreeList; + while (nsnull != psd) { + PerSpanData* nextSpan = psd->mNext; + if ((psd < &mSpanDataBuf[0]) || (psd >= &mSpanDataBuf[NUM_SPAN_DATA])) { + delete psd; + } + psd = nextSpan; + } + + // Free up all of the per-frame-data items that were allocated on the heap + PerFrameData* pfd = mFrameFreeList; + while (nsnull != pfd) { + PerFrameData* nextFrame = pfd->mNext; + if ((pfd < &mFrameDataBuf[0]) || (pfd >= &mFrameDataBuf[NUM_FRAME_DATA])) { + delete pfd; + } + pfd = nextFrame; + } } void -nsLineLayout::EndTextRun() +nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aIsTopOfPage) { - mNewTextRun = nsnull; + NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user"); +#ifdef DEBUG + if ((aWidth > 200000) && (aWidth != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": Init: bad caller: width WAS %d(0x%x)\n", + aWidth, aWidth); + aWidth = NS_UNCONSTRAINEDSIZE; + } + if ((aHeight > 200000) && (aHeight != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": Init: bad caller: height WAS %d(0x%x)\n", + aHeight, aHeight); + aHeight = NS_UNCONSTRAINEDSIZE; + } +#endif +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": BeginLineReflow: %d,%d,%d,%d %s\n", + aX, aY, aWidth, aHeight, + aIsTopOfPage ? "top-of-page" : ""); +#endif + + mBRFrame = nsnull; + mColumn = 0; + mEndsInWhiteSpace = PR_TRUE; + mUnderstandsWhiteSpace = PR_FALSE; + mFirstLetterStyleOK = PR_FALSE; + mIsTopOfPage = aIsTopOfPage; + mCanBreakBeforeFrame = PR_FALSE; + mUpdatedBand = PR_FALSE; + mPlacedFloaters = 0; + mTotalPlacedFrames = 0; + mSpanDepth = 0; + mMaxTopBoxHeight = mMaxBottomBoxHeight = 0; + + ForgetWordFrames(); + + PerSpanData* psd; + NewPerSpanData(&psd); + mCurrentSpan = mRootSpan = psd; + psd->mReflowState = mBlockReflowState; + psd->mLeftEdge = aX; + psd->mX = aX; + if (NS_UNCONSTRAINEDSIZE == aWidth) { + psd->mRightEdge = NS_UNCONSTRAINEDSIZE; + } + else { + psd->mRightEdge = aX + aWidth; + } + + mTopEdge = aY; + if (NS_UNCONSTRAINEDSIZE == aHeight) { + mBottomEdge = NS_UNCONSTRAINEDSIZE; + } + else { + mBottomEdge = aY + aHeight; + } +} + +void +nsLineLayout::EndLineReflow() +{ +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": EndLineReflow: width=%d\n", mRootSpan->mX - mRootSpan->mLeftEdge); +#endif + + PerSpanData* psd = mRootSpan; + while (nsnull != psd) { + // Put frames on free list + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + PerFrameData* nextFrame = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + pfd = nextFrame; + } + + // Put span on free list + PerSpanData* nextSpan = psd->mNext; + psd->mNext = mSpanFreeList; + mSpanFreeList = psd; + psd = nextSpan; + } + mCurrentSpan = mRootSpan = mLastSpan = nsnull; +} + +void +nsLineLayout::UpdateBand(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aPlacedLeftFloater) +{ + PerSpanData* psd = mRootSpan; + NS_PRECONDITION(psd->mX == psd->mLeftEdge, "update-band called late"); +#ifdef DEBUG + if ((aWidth > 200000) && (aWidth != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: bad caller: width WAS %d(0x%x)\n", + aWidth, aWidth); + aWidth = NS_UNCONSTRAINEDSIZE; + } + if ((aHeight > 200000) && (aHeight != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: bad caller: height WAS %d(0x%x)\n", + aHeight, aHeight); + aHeight = NS_UNCONSTRAINEDSIZE; + } +#endif +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: %d,%d,%d,%d %s\n", + aX, aY, aWidth, aHeight, + aPlacedLeftFloater ? "placed-left-floater" : ""); +#endif + + psd->mLeftEdge = aX; + psd->mX = aX; + if (NS_UNCONSTRAINEDSIZE == aWidth) { + psd->mRightEdge = NS_UNCONSTRAINEDSIZE; + } + else { + psd->mRightEdge = aX + aWidth; + } + mTopEdge = aY; + if (NS_UNCONSTRAINEDSIZE == aHeight) { + mBottomEdge = NS_UNCONSTRAINEDSIZE; + } + else { + mBottomEdge = aY + aHeight; + } + mUpdatedBand = PR_TRUE; + mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT); +} + +void +nsLineLayout::UpdateFrames() +{ + if (NS_STYLE_DIRECTION_LTR == mDirection) { + if (PLACED_LEFT & mPlacedFloaters) { + // Note: Only adjust the outermost frames (the ones that are + // direct children of the block), not the ones in the child + // spans. The reason is simple: the frames in the spans have + // coordinates local to their parent therefore they are moved + // when their parent span is moved. + PerSpanData* psd = mRootSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + pfd->mBounds.x = psd->mX; + pfd = pfd->mNext; + } + } + } + else if (PLACED_RIGHT & mPlacedFloaters) { + // XXX handle DIR=right-to-left + } } nsresult -nsLineLayout::AddText(nsIFrame* aTextFrame) +nsLineLayout::NewPerSpanData(PerSpanData** aResult) { - if (nsnull == mNewTextRun) { - mNewTextRun = new nsTextRun(); - if (nsnull == mNewTextRun) { + PerSpanData* psd = mSpanFreeList; + if (nsnull == psd) { + psd = new PerSpanData; + if (nsnull == psd) { return NS_ERROR_OUT_OF_MEMORY; } - *mTextRunP = mNewTextRun; - mTextRunP = &mNewTextRun->mNext; } - mNewTextRun->mArray.AppendElement(aTextFrame); - return NS_OK;/* XXX */ + else { + mSpanFreeList = psd->mNext; + } + psd->mParent = nsnull; + psd->mFrame = nsnull; + psd->mFirstFrame = nsnull; + psd->mLastFrame = nsnull; + psd->mNext = nsnull; + + // Link new span to the end of the span list + if (nsnull == mLastSpan) { + psd->mPrev = nsnull; + } + else { + mLastSpan->mNext = psd; + psd->mPrev = mLastSpan; + } + mLastSpan = psd; + + *aResult = psd; + return NS_OK; } -nsTextRun* -nsLineLayout::FindTextRunFor(nsIFrame* aFrame) +nsresult +nsLineLayout::BeginSpan(nsIFrame* aFrame, + const nsHTMLReflowState* aSpanReflowState, + nscoord aLeftEdge, + nscoord aRightEdge) { - // Only the first-in-flows are present in the text run list so - // backup from the argument frame to its first-in-flow. - for (;;) { - nsIFrame* prevInFlow; - aFrame->GetPrevInFlow(&prevInFlow); - if (nsnull == prevInFlow) { - break; +#ifdef NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth+1); + nsFrame::ListTag(stdout, aFrame); + printf(": BeginSpan leftEdge=%d rightEdge=%d\n", aLeftEdge, aRightEdge); +#endif + + PerSpanData* psd; + nsresult rv = NewPerSpanData(&psd); + if (NS_SUCCEEDED(rv)) { + // Link up span frame's pfd to point to its child span data + PerFrameData* pfd = mCurrentSpan->mLastFrame; + NS_ASSERTION(pfd->mFrame == aFrame, "huh?"); + pfd->mSpan = psd; + + // Init new span + psd->mFrame = pfd; + psd->mParent = mCurrentSpan; + psd->mReflowState = aSpanReflowState; + psd->mLeftEdge = aLeftEdge; + psd->mX = aLeftEdge; + psd->mRightEdge = aRightEdge; + + // Switch to new span + mCurrentSpan = psd; + mSpanDepth++; + } + return rv; +} + +void +nsLineLayout::EndSpan(nsIFrame* aFrame, + nsSize& aSizeResult, + nsSize* aMaxElementSize) +{ + NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span"); +#ifdef NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + nsFrame::ListTag(stdout, aFrame); + printf(": EndSpan width=%d\n", mCurrentSpan->mX - mCurrentSpan->mLeftEdge); +#endif + PerSpanData* psd = mCurrentSpan; + nscoord width = 0; + nscoord maxHeight = 0; + nscoord maxElementWidth = 0; + nscoord maxElementHeight = 0; + if (nsnull != psd->mLastFrame) { + width = psd->mX - psd->mLeftEdge; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height; + + // Compute max-element-size if necessary + if (aMaxElementSize) { + nscoord mw = pfd->mMaxElementSize.width + + pfd->mMargin.left + pfd->mMargin.right; + if (maxElementWidth < mw) { + maxElementWidth = mw; + } + nscoord mh = pfd->mMaxElementSize.height + + pfd->mMargin.top + pfd->mMargin.bottom; + if (maxElementHeight < mh) { + maxElementHeight = mh; + } + } + pfd = pfd->mNext; } - aFrame = prevInFlow; + } + aSizeResult.width = width; + aSizeResult.height = maxHeight; + if (aMaxElementSize) { + aMaxElementSize->width = maxElementWidth; + aMaxElementSize->height = maxElementHeight; } - // Now look for the frame in each run - nsTextRun* run = mReflowTextRuns; - while (nsnull != run) { - PRInt32 ix = run->mArray.IndexOf(aFrame); - if (ix >= 0) { - return run; - } - run = run->mNext; + mSpanDepth--; + mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out! + mCurrentSpan = mCurrentSpan->mParent; +} + +PRInt32 +nsLineLayout::GetCurrentSpanCount() const +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + PRInt32 count = 0; + PerFrameData* pfd = mRootSpan->mFirstFrame; + while (nsnull != pfd) { + count++; + pfd = pfd->mNext; + } + return count; +} + +void +nsLineLayout::SplitLineTo(PRInt32 aNewCount) +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + +#ifdef REALLY_NOISY_PUSHING + printf("SplitLineTo %d (current count=%d); before:\n", aNewCount, + GetCurrentSpanCount()); + DumpPerSpanData(mRootSpan, 1); +#endif + PerSpanData* psd = mRootSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (--aNewCount == 0) { + // Truncate list at pfd (we keep pfd, but anything following is freed) + PerFrameData* next = pfd->mNext; + pfd->mNext = nsnull; + psd->mLastFrame = pfd; + + // Now release all of the frames following pfd + pfd = next; + while (nsnull != pfd) { + next = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } + pfd = next; + } + break; + } + pfd = pfd->mNext; + } +#ifdef NOISY_PUSHING + printf("SplitLineTo %d (current count=%d); after:\n", aNewCount, + GetCurrentSpanCount()); + DumpPerSpanData(mRootSpan, 1); +#endif +} + +void +nsLineLayout::PushFrame(nsIFrame* aFrame) +{ + PerSpanData* psd = mCurrentSpan; + NS_ASSERTION(psd->mLastFrame->mFrame == aFrame, "pushing non-last frame"); + +#ifdef REALLY_NOISY_PUSHING + nsFrame::IndentBy(stdout, mSpanDepth); + printf("PushFrame %p, before:\n", psd); + DumpPerSpanData(psd, 1); +#endif + + // Take the last frame off of the span's frame list + PerFrameData* pfd = psd->mLastFrame; + if (pfd == psd->mFirstFrame) { + // We are pushing away the only frame...empty the list + psd->mFirstFrame = nsnull; + psd->mLastFrame = nsnull; + } + else { + PerFrameData* prevFrame = pfd->mPrev; + prevFrame->mNext = nsnull; + psd->mLastFrame = prevFrame; + } + + // Now free it, and if it has a span, free that too + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } +#ifdef NOISY_PUSHING + nsFrame::IndentBy(stdout, mSpanDepth); + printf("PushFrame: %p after:\n", psd); + DumpPerSpanData(psd, 1); +#endif +} + +void +nsLineLayout::FreeSpan(PerSpanData* psd) +{ + // Take span out of the list + if (nsnull != psd->mNext) psd->mNext->mPrev = psd->mPrev; + if (nsnull != psd->mPrev) psd->mPrev->mNext = psd->mNext; + + // Free its frames + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } + PerFrameData* next = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + pfd = next; + } +} + +PRBool +nsLineLayout::IsZeroHeight() +{ + PerSpanData* psd = mCurrentSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (0 != pfd->mBounds.height) { + return PR_FALSE; + } + pfd = pfd->mNext; + } + return PR_TRUE; +} + +nsresult +nsLineLayout::NewPerFrameData(PerFrameData** aResult) +{ + PerFrameData* pfd = mFrameFreeList; + if (nsnull == pfd) { + pfd = new PerFrameData; + if (nsnull == pfd) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + else { + mFrameFreeList = pfd->mNext; + } + pfd->mSpan = nsnull; + pfd->mNext = nsnull; + *aResult = pfd; + return NS_OK; +} + +nsresult +nsLineLayout::ReflowFrame(nsIFrame* aFrame, + nsIFrame** aNextRCFrame, + nsReflowStatus& aReflowStatus) +{ + PerFrameData* pfd; + nsresult rv = NewPerFrameData(&pfd); + if (NS_FAILED(rv)) { + return rv; + } + PerSpanData* psd = mCurrentSpan; + psd->AppendFrame(pfd); + +#ifdef REALLY_NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + printf("%p: Begin ReflowFrame pfd=%p ", psd, pfd); + nsFrame::ListTag(stdout, aFrame); + printf("\n"); +#endif + + // Compute the available size for the frame. This available width + // includes room for the side margins and for the text-indent. + nsSize availSize; + if (NS_UNCONSTRAINEDSIZE == psd->mRightEdge) { + availSize.width = NS_UNCONSTRAINEDSIZE; + } + else { + availSize.width = psd->mRightEdge - psd->mX; + if (mNoWrap) { + // XXX Shouldn't this use NS_UNCONSTRAINEDSIZE? + availSize.width = psd->mReflowState->availableWidth; + } + } + if (NS_UNCONSTRAINEDSIZE == mBottomEdge) { + availSize.height = NS_UNCONSTRAINEDSIZE; + } + else { + availSize.height = mBottomEdge - mTopEdge; + } + + // Get reflow reason set correctly. It's possible that a child was + // created and then it was decided that it could not be reflowed + // (for example, a block frame that isn't at the start of a + // line). In this case the reason will be wrong so we need to check + // the frame state. + nsReflowReason reason = eReflowReason_Resize; + nsFrameState state; + aFrame->GetFrameState(&state); + if (NS_FRAME_FIRST_REFLOW & state) { + reason = eReflowReason_Initial; + } + else if (*aNextRCFrame == aFrame) { + reason = eReflowReason_Incremental; + // Make sure we only incrementally reflow once + *aNextRCFrame = nsnull; + } + + // Setup reflow state for reflowing the frame + nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState, aFrame, + availSize, reason); + reflowState.lineLayout = this; + reflowState.isTopOfPage = mIsTopOfPage; + mUnderstandsWhiteSpace = PR_FALSE; + mCanBreakBeforeFrame = mTotalPlacedFrames > 0; + + // Stash copies of some of the computed state away for later + // (vertical alignment, for example) + pfd->mFrame = aFrame; + pfd->mMargin = reflowState.computedMargin; + pfd->mBorderPadding = reflowState.mComputedBorderPadding; + pfd->mFrameType = reflowState.frameType; + pfd->mRelativePos = + reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE; + if (pfd->mRelativePos) { + pfd->mOffsets = reflowState.computedOffsets; + } + + // Capture this state *before* we reflow the frame in case it clears + // the state out. We need to know how to treat the current frame + // when breaking. + mWasInWord = InWord(); + + // Apply left margins (as appropriate) to the frame computing the + // new starting x,y coordinates for the frame. + ApplyLeftMargin(pfd, reflowState); + + // Let frame know that are reflowing it + nscoord x = pfd->mBounds.x; + nscoord y = pfd->mBounds.y; + nsIHTMLReflow* htmlReflow; + + aFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + htmlReflow->WillReflow(mPresContext); + + // Adjust spacemanager coordinate system for the frame. The + // spacemanager coordinates are inside the current spans + // border+padding, but the x/y coordinates are not (recall that + // frame coordinates are relative to the parents origin and that the + // parents border/padding is inside the parent + // frame. Therefore we have to subtract out the parents + // border+padding before translating. + nsSize innerMaxElementSize; + nsHTMLReflowMetrics metrics(mComputeMaxElementSize + ? &innerMaxElementSize + : nsnull); +#ifdef DEBUG + if (mComputeMaxElementSize) { + metrics.maxElementSize->width = nscoord(0xdeadbeef); + metrics.maxElementSize->height = nscoord(0xdeadbeef); + } +#endif + nscoord tx = x - psd->mReflowState->mComputedBorderPadding.left; + nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top; + mSpaceManager->Translate(tx, ty); + htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus); + mSpaceManager->Translate(-tx, -ty); + +#ifdef DEBUG_kipp + NS_ASSERTION((metrics.width > -200000) && (metrics.width < 200000), "oy"); + NS_ASSERTION((metrics.height > -200000) && (metrics.height < 200000), "oy"); +#endif +#ifdef DEBUG + if (mComputeMaxElementSize && + ((nscoord(0xdeadbeef) == metrics.maxElementSize->width) || + (nscoord(0xdeadbeef) == metrics.maxElementSize->height))) { + printf("nsLineLayout: "); + nsFrame::ListTag(stdout, aFrame); + printf(" didn't set max-element-size!\n"); + metrics.maxElementSize->width = 0; + metrics.maxElementSize->height = 0; + } +#endif + + aFrame->GetFrameState(&state); + if (NS_FRAME_OUTSIDE_CHILDREN & state) { + pfd->mCombinedArea = metrics.mCombinedArea; + } + else { + pfd->mCombinedArea.x = 0; + pfd->mCombinedArea.y = 0; + pfd->mCombinedArea.width = metrics.width; + pfd->mCombinedArea.height = metrics.height; + } + pfd->mBounds.width = metrics.width; + pfd->mBounds.height = metrics.height; + if (mComputeMaxElementSize) { + pfd->mMaxElementSize = *metrics.maxElementSize; + } + + // Now that frame has been reflowed at least one time make sure that + // the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an + // initial reflow reason again. + if (eReflowReason_Initial == reason) { + aFrame->GetFrameState(&state); + aFrame->SetFrameState(state & ~NS_FRAME_FIRST_REFLOW); + } + + if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) { + // If frame is complete and has a next-in-flow, we need to delete + // them now. Do not do this when a break-before is signaled because + // the frame is going to get reflowed again (and may end up wanting + // a next-in-flow where it ends up). + if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { + nsIFrame* kidNextInFlow; + aFrame->GetNextInFlow(&kidNextInFlow); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows. Make sure that we ask + // the right parent to do the removal (it's possible that the + // parent is not this because we are executing pullup code) + nsHTMLContainerFrame* parent; + aFrame->GetParent((nsIFrame**) &parent); + parent->DeleteChildsNextInFlow(mPresContext, aFrame); + } + } + + // See if we can place the frame. If we can't fit it, then we + // return now. + if (CanPlaceFrame(pfd, reflowState, metrics, aReflowStatus)) { + // Place the frame, updating aBounds with the final size and + // location. Then apply the bottom+right margins (as + // appropriate) to the frame. + PlaceFrame(pfd, metrics); + PerSpanData* span = pfd->mSpan; + if (span) { + // The frame we just finished reflowing is an inline + // container. It needs its child frames vertically aligned, + // so do most of it now. + VerticalAlignFrames(span); + } + } + else { + PushFrame(aFrame); + } + } + else { + PushFrame(aFrame); + } + +#ifdef REALLY_NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + printf("End ReflowFrame "); + nsFrame::ListTag(stdout, aFrame); + printf(" status=%x\n", aReflowStatus); +#endif + return rv; +} + +void +nsLineLayout::ApplyLeftMargin(PerFrameData* pfd, + nsHTMLReflowState& aReflowState) +{ + // If this is the first frame in the block, and its the first line + // of a block then see if the text-indent property amounts to + // anything. + nscoord indent = 0; + if (InBlockContext() && (0 == mLineNumber) && + (0 == mTotalPlacedFrames)) { + nsStyleUnit unit = mStyleText->mTextIndent.GetUnit(); + if (eStyleUnit_Coord == unit) { + indent = mStyleText->mTextIndent.GetCoordValue(); + } + else if (eStyleUnit_Percent == unit) { + nscoord width = + nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState->parentReflowState); + if (0 != width) { + indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width); + } + } + } + + // Adjust available width to account for the indent and the margins + aReflowState.availableWidth -= indent + pfd->mMargin.left + + pfd->mMargin.right; + + // NOTE: While the x coordinate remains relative to the parent span, + // the y coordinate is fixed at the top edge for the line. During + // VerticalAlignFrames we will repair this so that the y coordinate + // is properly set and relative to the appropriate span. + PerSpanData* psd = mCurrentSpan; + pfd->mBounds.x = psd->mX + indent; + pfd->mBounds.y = mTopEdge; + + // Compute left margin + nsIFrame* prevInFlow; + switch (aReflowState.mStyleDisplay->mFloats) { + default: + NS_NOTYETIMPLEMENTED("Unsupported floater type"); + // FALL THROUGH + + case NS_STYLE_FLOAT_LEFT: + case NS_STYLE_FLOAT_RIGHT: + // When something is floated, its margins are applied there + // not here. + break; + + case NS_STYLE_FLOAT_NONE: + // Only apply left-margin on the first-in flow for inline frames + pfd->mFrame->GetPrevInFlow(&prevInFlow); + if (nsnull != prevInFlow) { + // Zero this out so that when we compute the max-element-size + // of the frame we will properly avoid adding in the left + // margin. + pfd->mMargin.left = 0; + } + pfd->mBounds.x += pfd->mMargin.left; + break; + } +} + +/** + * See if the frame can be placed now that we know it's desired size. + * We can always place the frame if the line is empty. Note that we + * know that the reflow-status is not a break-before because if it was + * ReflowFrame above would have returned false, preventing this method + * from being called. The logic in this method assumes that. + * + * Note that there is no check against the Y coordinate because we + * assume that the caller will take care of that. + */ +PRBool +nsLineLayout::CanPlaceFrame(PerFrameData* pfd, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) +{ + // Compute right margin to use + nscoord rightMargin = 0; + if (0 != pfd->mBounds.width) { + switch (aReflowState.mStyleDisplay->mFloats) { + default: + NS_NOTYETIMPLEMENTED("Unsupported floater type"); + // FALL THROUGH + + case NS_STYLE_FLOAT_LEFT: + case NS_STYLE_FLOAT_RIGHT: + // When something is floated, its margins are applied there + // not here. + break; + + case NS_STYLE_FLOAT_NONE: + // Only apply right margin for the last-in-flow + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + // Zero this out so that when we compute the + // max-element-size of the frame we will properly avoid + // adding in the right margin. + pfd->mMargin.right = 0; + } + rightMargin = pfd->mMargin.right; + break; + } + } + pfd->mMargin.right = rightMargin; + + // Set outside to PR_TRUE if the result of the reflow leads to the + // frame sticking outside of our available area. + PerSpanData* psd = mCurrentSpan; + PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge; + + // There are several special conditions that exist which allow us to + // ignore outside. If they are true then we can place frame and + // return PR_TRUE. + if (!mCanBreakBeforeFrame || mWasInWord || mNoWrap) { + return PR_TRUE; + } + + if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) { + // Empty frames always fit right where they are + return PR_TRUE; + } + + if (pfd == mCurrentSpan->mFirstFrame) { + return PR_TRUE; + } + + if (outside) { + aStatus = NS_INLINE_LINE_BREAK_BEFORE(); + return PR_FALSE; + } + return PR_TRUE; +} + +/** + * Place the frame. Update running counters. + */ +void +nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics) +{ + // If frame is zero width then do not apply its left and right margins. + PerSpanData* psd = mCurrentSpan; + PRBool emptyFrame = PR_FALSE; + if ((0 == pfd->mBounds.width) && (0 == pfd->mBounds.height)) { + pfd->mBounds.x = psd->mX; + pfd->mBounds.y = mTopEdge; + emptyFrame = PR_TRUE; + } + + // Record ascent and update max-ascent and max-descent values + pfd->mAscent = aMetrics.ascent; + pfd->mDescent = aMetrics.descent; + pfd->mCarriedOutTopMargin = aMetrics.mCarriedOutTopMargin; + pfd->mCarriedOutBottomMargin = aMetrics.mCarriedOutBottomMargin; + + // If the band was updated during the reflow of that frame then we + // need to adjust any prior frames that were reflowed. + if (mUpdatedBand && InBlockContext()) { + UpdateFrames(); + mUpdatedBand = PR_FALSE; + } + + // Advance to next X coordinate + psd->mX = pfd->mBounds.XMost() + pfd->mMargin.right; + + // If the frame is a not aware of white-space and it takes up some + // area, disable leading white-space compression for the next frame + // to be reflowed. + if (!mUnderstandsWhiteSpace && !emptyFrame) { + mEndsInWhiteSpace = PR_FALSE; + } + + // Compute the bottom margin to apply. Note that the margin only + // applies if the frame ends up with a non-zero height. + if (!emptyFrame) { + // Inform line layout that we have placed a non-empty frame + mTotalPlacedFrames++; + } +} + +nsresult +nsLineLayout::AddBulletFrame(nsIFrame* aFrame, + const nsHTMLReflowMetrics& aMetrics) +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + + PerFrameData* pfd; + nsresult rv = NewPerFrameData(&pfd); + if (NS_SUCCEEDED(rv)) { + mRootSpan->AppendFrame(pfd); + pfd->mFrame = aFrame; + pfd->mMargin.SizeTo(0, 0, 0, 0); + pfd->mBorderPadding.SizeTo(0, 0, 0, 0); + pfd->mFrameType = NS_CSS_FRAME_TYPE_INLINE|NS_FRAME_REPLACED_ELEMENT; + pfd->mRelativePos = PR_FALSE; + pfd->mAscent = aMetrics.ascent; + pfd->mDescent = aMetrics.descent; + aFrame->GetRect(pfd->mBounds); // y value is irrelevant + pfd->mCombinedArea = aMetrics.mCombinedArea; + if (mComputeMaxElementSize) { + pfd->mMaxElementSize.SizeTo(aMetrics.width, aMetrics.height); + } + } + return rv; +} + +#ifdef DEBUG +void +nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent) +{ + nsFrame::IndentBy(stdout, aIndent); + printf("%p: left=%d x=%d right=%d prev/next=%p/%p\n", psd, psd->mLeftEdge, + psd->mX, psd->mRightEdge, psd->mPrev, psd->mNext); + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nsFrame::IndentBy(stdout, aIndent+1); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(" %d,%d,%d,%d\n", pfd->mBounds.x, pfd->mBounds.y, + pfd->mBounds.width, pfd->mBounds.height); + if (pfd->mSpan) { + DumpPerSpanData(pfd->mSpan, aIndent + 1); + } + pfd = pfd->mNext; + } +} +#endif + +#define VALIGN_OTHER 0 +#define VALIGN_TOP 1 +#define VALIGN_BOTTOM 2 + +void +nsLineLayout::VerticalAlignFrames(nsRect& aLineBoxResult, + nsSize& aMaxElementSizeResult) +{ + // Synthesize a PerFrameData for the block frame + PerFrameData rootPFD; + rootPFD.mFrame = mBlockReflowState->frame; + rootPFD.mFrameType = mBlockReflowState->frameType; + rootPFD.mAscent = 0; + rootPFD.mDescent = 0; + mRootSpan->mFrame = &rootPFD; + + // Partially place the children of the block frame. The baseline for + // this operation is set to zero so that the y coordinates for all + // of the placed children will be relative to there. + PerSpanData* psd = mRootSpan; + VerticalAlignFrames(psd); + + // Compute the line-height. The line-height will be the larger of: + // + // [1] maxY - minY (the distance between the highest childs top edge + // and the lowest childs bottom edge) + // + // [2] the maximum logical box height (since not every frame may have + // participated in #1; for example: top/bottom aligned frames) + // + // [3] the minimum line height (line-height property set on the + // block frame) + nscoord lineHeight = psd->mMaxY - psd->mMinY; + + // Now that the line-height is computed, we need to know where the + // baseline is in the line. Position baseline so that mMinY is just + // inside the top of the line box. + nscoord baselineY; + if (psd->mMinY < 0) { + baselineY = mTopEdge - psd->mMinY; + } + else { + baselineY = mTopEdge; + } + + // It's possible that the line-height isn't tall enough because of + // the blocks minimum line-height. + if (0 != lineHeight) { + // If line contains nothing but empty boxes that have no height + // then don't apply the min-line-height. + // + // Note: This is how we hide lines that contain nothing but + // compressed whitespace. + if (lineHeight < mMinLineHeight) { + // Apply half of the extra space to the top of the line as top + // leading + nscoord extra = mMinLineHeight - lineHeight; + baselineY += extra / 2; + lineHeight = mMinLineHeight; + } + } + + // It's also possible that the line-height isn't tall enough because + // of top/bottom aligned elements that were not accounted for in + // min/max Y. + // + // The CSS2 spec doesn't really say what happens when to the + // baseline in this situations. What we do is if the largest top + // aligned box height is greater than the line-height then we leave + // the baseline alone. If the largest bottom aligned box is greater + // than the line-height then we slide the baseline down by the extra + // amount. + // + // Navigator 4 gives precedence to the first top/bottom aligned + // object. We just let bottom aligned objects win. + if (lineHeight < mMaxBottomBoxHeight) { + // When the line is shorter than the maximum top aligned box + nscoord extra = mMaxBottomBoxHeight - lineHeight; + baselineY += extra; + lineHeight = mMaxBottomBoxHeight; + } + if (lineHeight < mMaxTopBoxHeight) { + lineHeight = mMaxTopBoxHeight; + } +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> lineHeight=%d baselineY=%d\n", lineHeight, baselineY); +#endif + + // Now position all of the frames in the root span. We will also + // recurse over the child spans and place any top/bottom aligned + // frames we find. + // XXX PERFORMANCE: set a bit per-span to avoid the extra work + // (propogate it upward too) + PerFrameData* pfd = psd->mFirstFrame; + nscoord maxElementWidth = 0; + nscoord maxElementHeight = 0; + while (nsnull != pfd) { + // Compute max-element-size if necessary + if (mComputeMaxElementSize) { + nscoord mw = pfd->mMaxElementSize.width + + pfd->mMargin.left + pfd->mMargin.right; + if (maxElementWidth < mw) { + maxElementWidth = mw; + } + nscoord mh = pfd->mMaxElementSize.height + + pfd->mMargin.top + pfd->mMargin.bottom; + if (maxElementHeight < mh) { + maxElementHeight = mh; + } + } + PerSpanData* span = pfd->mSpan; + switch (pfd->mVerticalAlign) { + case VALIGN_TOP: + if (span) { + pfd->mBounds.y = mTopEdge - pfd->mBorderPadding.top + + span->mTopLeading; + } + else { + pfd->mBounds.y = mTopEdge + pfd->mMargin.top; + } + break; + case VALIGN_BOTTOM: + if (span) { + // Compute bottom leading + pfd->mBounds.y = mTopEdge + lineHeight - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + span->mBottomLeading; + } + else { + pfd->mBounds.y = mTopEdge + lineHeight - pfd->mMargin.bottom - + pfd->mBounds.height; + } + break; + case VALIGN_OTHER: + pfd->mBounds.y += baselineY; + break; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d\n", pfd->mBounds.y); +#endif + if (span) { + nscoord distanceFromTop = pfd->mBounds.y - mTopEdge; + PlaceTopBottomFrames(span, distanceFromTop, lineHeight); + } + pfd = pfd->mNext; + } + + // Fill in returned line-box and max-element-size data + aLineBoxResult.x = psd->mLeftEdge; + aLineBoxResult.y = mTopEdge; + aLineBoxResult.width = psd->mX - psd->mLeftEdge; + aLineBoxResult.height = lineHeight; + aMaxElementSizeResult.width = maxElementWidth; + aMaxElementSizeResult.height = maxElementHeight; + + // Undo root-span mFrame pointer to prevent brane damage later on... + mRootSpan->mFrame = nsnull; +} + +void +nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd, + nscoord aDistanceFromTop, + nscoord aLineHeight) +{ + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + PerSpanData* span = pfd->mSpan; + switch (pfd->mVerticalAlign) { + case VALIGN_TOP: + if (span) { + pfd->mBounds.y = -aDistanceFromTop - pfd->mBorderPadding.top + + span->mTopLeading; + } + else { + pfd->mBounds.y = -aDistanceFromTop + pfd->mMargin.top; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n", + pfd->mBounds.y, aDistanceFromTop, + span ? pfd->mBorderPadding.top : 0, + span ? span->mTopLeading : 0); +#endif + break; + case VALIGN_BOTTOM: + if (span) { + // Compute bottom leading + pfd->mBounds.y = -aDistanceFromTop + aLineHeight - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + span->mBottomLeading; + } + else { + pfd->mBounds.y = -aDistanceFromTop + aLineHeight - + pfd->mMargin.bottom - pfd->mBounds.height; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d\n", pfd->mBounds.y); +#endif + break; + } + if (span) { + nscoord distanceFromTop = distanceFromTop + pfd->mBounds.y; + PlaceTopBottomFrames(span, distanceFromTop, aLineHeight); + } + pfd = pfd->mNext; + } +} + +// Vertically place frames within a given span. Note: this doesn't +// place top/bottom aligned frames as those have to wait until the +// entire line box height is known. This is called after the span +// frame has finished being reflowed so that we know its height. +void +nsLineLayout::VerticalAlignFrames(PerSpanData* psd) +{ + // Get parent frame info + PerFrameData* parentPFD = psd->mFrame; + nsIFrame* parentFrame = parentPFD->mFrame; + + // Get the parent frame's font for all of the frames in this span + const nsStyleFont* parentFont; + parentFrame->GetStyleData(eStyleStruct_Font, + (const nsStyleStruct*&)parentFont); + nsIRenderingContext* rc = mBlockReflowState->rendContext; + rc->SetFont(parentFont->mFont); + nsIFontMetrics* fm; + rc->GetFontMetrics(fm); + + + // Setup baselineY, minY, and maxY + nscoord baselineY, minY, maxY; + if (psd == mRootSpan) { + // Use a zero baselineY since we don't yet know where the baseline + // will be (until we know how tall the line is; then we will + // know). In addition, use extreme values for the minY and maxY + // values so that only the child frames will impact their values + // (since these are children of the block, there is no span box to + // provide initial values). + baselineY = 0; + minY = 0; + maxY = 0; +#ifdef NOISY_VERTICAL_ALIGN + nsFrame::ListTag(stdout, parentFrame); + printf(": pass1 valign frames: topEdge=%d minLineHeight=%d\n", + mTopEdge, mMinLineHeight); +#endif + } + else if (0 != parentPFD->mBounds.height) { + // Compute the logical height for this span. Also compute the top + // leading. + nscoord logicalHeight = + nsHTMLReflowState::CalcLineHeight(mPresContext, parentFrame); + nscoord contentHeight = parentPFD->mBounds.height - + parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom; + nscoord leading = logicalHeight - contentHeight; + psd->mTopLeading = leading / 2; + psd->mBottomLeading = leading - psd->mTopLeading; + psd->mLogicalHeight = logicalHeight; + + // The initial values for the min and max Y values are in the spans + // coordinate space, and cover the logical height of the span. If + // there are child frames in this span that stick out of this area + // then the minY and maxY are updated by the amount of logical + // height that is outside this range. + minY = parentPFD->mBorderPadding.top - psd->mTopLeading; + maxY = minY + psd->mLogicalHeight; + + // This is the distance from the top edge of the parents visual + // box to the baseline. + nscoord parentAscent; + fm->GetMaxAscent(parentAscent); + baselineY = parentAscent + parentPFD->mBorderPadding.top; +#ifdef NOISY_VERTICAL_ALIGN + nsFrame::ListTag(stdout, parentFrame); + printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d\n", + baselineY, logicalHeight, psd->mTopLeading, + parentPFD->mBounds.height, + parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom); +#endif + } + else { + // When a span container is zero height it means that all of its + // kids are zero height as well. + psd->mMinY = 0; + psd->mMaxY = 0; + psd->mTopLeading = 0; + psd->mBottomLeading = 0; + psd->mLogicalHeight = 0; +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> [empty line]\n"); +#endif + return; + } + + nscoord maxTopBoxHeight = 0; + nscoord maxBottomBoxHeight = 0; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nsIFrame* frame = pfd->mFrame; + + // Compute the logical height of the frame + nscoord logicalHeight; + nscoord topLeading; + PerSpanData* frameSpan = pfd->mSpan; + if (frameSpan) { + // For span frames the logical-height and top-leading was + // pre-computed when the span was reflowed. + logicalHeight = frameSpan->mLogicalHeight; + topLeading = frameSpan->mTopLeading; + } + else { + // For other elements the logical height is the same as the + // frames height plus its margins. + logicalHeight = pfd->mBounds.height + pfd->mMargin.top + + pfd->mMargin.bottom; + topLeading = 0; + } + + // Get vertical-align property + const nsStyleText* textStyle; + frame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)textStyle); + nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit(); + if (eStyleUnit_Inherit == verticalAlignUnit) { + printf("XXX: vertical-align: inherit not implemented for "); + nsFrame::ListTag(stdout, frame); + printf("\n"); + } + PRUint8 verticalAlignEnum; + nscoord parentAscent, parentDescent, parentXHeight; + nscoord parentSuperscript, parentSubscript; + nscoord coordOffset, percentOffset, elementLineHeight; + nscoord revisedBaselineY; + switch (verticalAlignUnit) { + case eStyleUnit_Enumerated: + default: + if (eStyleUnit_Enumerated == verticalAlignUnit) { + verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue(); + } + else { + verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BASELINE; + } + switch (verticalAlignEnum) { + default: + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // The elements baseline is aligned with the baseline of + // the parent. + if (frameSpan) { + // XXX explain + pfd->mBounds.y = baselineY - pfd->mAscent; + } + else { + // For non-span elements the borders, padding and + // margins are significant. Use the visual box height + // and the bottom margin as the distance off of the + // baseline. + pfd->mBounds.y = baselineY - pfd->mAscent - pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_SUB: + // Lower the baseline of the box to the subscript offset + // of the parent's box. This is identical to the baseline + // alignment except for the addition of the subscript + // offset to the baseline Y. + fm->GetSubscriptOffset(parentSubscript); + revisedBaselineY = baselineY + parentSubscript; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_SUPER: + // Raise the baseline of the box to the superscript offset + // of the parent's box. This is identical to the baseline + // alignment except for the subtraction of the superscript + // offset to the baseline Y. + fm->GetSuperscriptOffset(parentSuperscript); + revisedBaselineY = baselineY - parentSuperscript; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + pfd->mVerticalAlign = VALIGN_TOP; + if (logicalHeight > maxTopBoxHeight) { + maxTopBoxHeight = logicalHeight; + } + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + pfd->mVerticalAlign = VALIGN_BOTTOM; + if (logicalHeight > maxBottomBoxHeight) { + maxBottomBoxHeight = logicalHeight; + } + break; + + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + // Align the midpoint of the frame with 1/2 the parents + // x-height above the baseline. + fm->GetXHeight(parentXHeight); + if (frameSpan) { + pfd->mBounds.y = baselineY - + (parentXHeight + pfd->mBounds.height)/2; + } + else { + pfd->mBounds.y = baselineY - (parentXHeight + logicalHeight)/2 + + pfd->mMargin.top; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP: + // The top of the logical box is aligned with the top of + // the parent elements text. + fm->GetMaxAscent(parentAscent); + if (frameSpan) { + pfd->mBounds.y = baselineY - parentAscent - + pfd->mBorderPadding.top + frameSpan->mTopLeading; + } + else { + pfd->mBounds.y = baselineY - parentAscent + pfd->mMargin.top; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM: + // The bottom of the logical box is aligned with the + // bottom of the parent elements text. + fm->GetMaxDescent(parentDescent); + if (frameSpan) { + pfd->mBounds.y = baselineY + parentDescent - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + frameSpan->mBottomLeading; + } + else { + pfd->mBounds.y = baselineY + parentDescent - + pfd->mBounds.height - pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + } + break; + + case eStyleUnit_Coord: + // According to the CSS2 spec (10.8.1), a positive value + // "raises" the box by the given distance while a negative value + // "lowers" the box by the given distance (with zero being the + // baseline). Since Y coordinates increase towards the bottom of + // the screen we reverse the sign. + coordOffset = textStyle->mVerticalAlign.GetCoordValue(); + revisedBaselineY = baselineY - coordOffset; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case eStyleUnit_Percent: + // Similar to a length value (eStyleUnit_Coord) except that the + // percentage is a function of the elements line-height value. + elementLineHeight = + nsHTMLReflowState::CalcLineHeight(mPresContext, frame); + percentOffset = nscoord( + textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight + ); + revisedBaselineY = baselineY - percentOffset; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + } + + // Update minY/maxY for frames that we just placed + if (pfd->mVerticalAlign == VALIGN_OTHER) { + nscoord yTop, yBottom; + if (frameSpan) { + // For spans that were are now placing, use their position + // plus their already computed min-Y and max-Y values for + // computing yTop and yBottom. + yTop = pfd->mBounds.y + frameSpan->mMinY; + yBottom = pfd->mBounds.y + frameSpan->mMaxY; + } + else { + yTop = pfd->mBounds.y - pfd->mMargin.top; + yBottom = yTop + logicalHeight; + } + if (yTop < minY) minY = yTop; + if (yBottom > maxY) maxY = yBottom; +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, frame); + printf(": raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n", + pfd->mAscent, pfd->mDescent, pfd->mBounds.height, + pfd->mBorderPadding.top, pfd->mBorderPadding.bottom, + logicalHeight, + pfd->mSpan ? topLeading : 0, + pfd->mBounds.y, minY, maxY); +#endif + if (psd != mRootSpan) { + frame->SetRect(pfd->mBounds); + } + } + pfd = pfd->mNext; + } + NS_RELEASE(fm); + psd->mMinY = minY; + psd->mMaxY = maxY; +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> minY=%d maxY=%d delta=%d maxBoxHeight=%d\n", + minY, maxY, maxY - minY, maxBoxHeight); +#endif + if (maxTopBoxHeight > mMaxTopBoxHeight) { + mMaxTopBoxHeight = maxTopBoxHeight; + } + if (maxBottomBoxHeight > mMaxBottomBoxHeight) { + mMaxBottomBoxHeight = maxBottomBoxHeight; + } +} + +void +nsLineLayout::TrimTrailingWhiteSpace(nsRect& aLineBounds) +{ +} + +void +nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify) +{ + PerSpanData* psd = mRootSpan; + nscoord availWidth = psd->mRightEdge; + if (NS_UNCONSTRAINEDSIZE == availWidth) { + // Don't bother horizontal aligning on pass1 table reflow +#ifdef REALLY_NOISY_HORIZONTAL_ALIGN + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": skipping horizontal alignment in pass1 table reflow\n"); +#endif + return; + } + availWidth -= psd->mLeftEdge; + nscoord remainingWidth = availWidth - aLineBounds.width; +#ifdef REALLY_NOISY_HORIZONTAL_ALIGN + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": availWidth=%d lineWidth=%d delta=%d\n", + availWidth, aLineBounds.width, remainingWidth); +#endif + if (remainingWidth > 0) { + nscoord dx = 0; + switch (mTextAlign) { + case NS_STYLE_TEXT_ALIGN_DEFAULT: + if (NS_STYLE_DIRECTION_LTR == mDirection) { + // default alignment for left-to-right is left so do nothing + break; + } + // Fall through to align right case for default alignment + // used when the direction is right-to-left. + + case NS_STYLE_TEXT_ALIGN_RIGHT: + dx = remainingWidth; + break; + + case NS_STYLE_TEXT_ALIGN_LEFT: + break; + + case NS_STYLE_TEXT_ALIGN_JUSTIFY: + // If this is not the last line then go ahead and justify the + // frames in the line. If it is the last line then if the + // direction is right-to-left then we right-align the frames. + if (aAllowJustify) { + break; + } + else if (NS_STYLE_DIRECTION_RTL == mDirection) { + // right align the frames + dx = remainingWidth;; + } + break; + + case NS_STYLE_TEXT_ALIGN_CENTER: + dx = remainingWidth / 2; + break; + } + if (0 != dx) { + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + pfd->mBounds.x += dx; + pfd->mFrame->SetRect(pfd->mBounds); + pfd = pfd->mNext; + } + } + } +} + +void +nsLineLayout::RelativePositionFrames(nsRect& aCombinedArea) +{ + RelativePositionFrames(mRootSpan, aCombinedArea); +} + +void +nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea) +{ + nsPoint origin; + nsRect spanCombinedArea; + PerFrameData* pfd; + + nscoord x0, y0, x1, y1; + if (nsnull != psd->mFrame) { + // The minimum combined area for the frames in a span covers the + // entire span frame. + pfd = psd->mFrame; + x0 = 0; + y0 = 0; + x1 = pfd->mBounds.width; + y1 = pfd->mBounds.height; + } + else { + // The minimum combined area for the frames that are direct + // children of the block starts at the upper left corner of the + // line but has no width or height. + x1 = x0 = psd->mLeftEdge; + y1 = y0 = mTopEdge; + } + + pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nscoord x = pfd->mBounds.x; + nscoord y = pfd->mBounds.y; + + // Adjust the origin of the frame + if (pfd->mRelativePos) { + nsIFrame* frame = pfd->mFrame; + frame->GetOrigin(origin); + // XXX what about right and bottom? + nscoord dx = pfd->mOffsets.left; + nscoord dy = pfd->mOffsets.top; + frame->MoveTo(origin.x + dx, origin.y + dy); + x += dx; + y += dy; + } + + // Note: the combined area of a child is in its coordinate + // system. We adjust the childs combined area into our coordinate + // system before computing the aggregated value by adding in + // x and y which were computed above. + nsRect* r = &pfd->mCombinedArea; + if (pfd->mSpan) { + // Compute a new combined area for the child span before + // aggregating it into our combined area. + r = &spanCombinedArea; + RelativePositionFrames(pfd->mSpan, spanCombinedArea); + } + + nscoord xl = x + r->x; + nscoord xr = x + r->XMost(); + if (xl < x0) x0 = xl; + if (xr > x1) x1 = xr; + nscoord yt = y + r->y; + nscoord yb = y + r->YMost(); + if (yt < y0) y0 = yt; + if (yb > y1) y1 = yb; + + pfd = pfd->mNext; + } + + // Compute aggregated combined area + aCombinedArea.x = x0; + aCombinedArea.y = y0; + aCombinedArea.width = x1 - x0; + aCombinedArea.height = y1 - y0; + + // If we just computed a spans combined area, we need to update its + // NS_FRAME_OUTSIDE_CHILDREN bit.. + if (nsnull != psd->mFrame) { + pfd = psd->mFrame; + nsIFrame* frame = pfd->mFrame; + nsFrameState oldState; + frame->GetFrameState(&oldState); + nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; + if ((x0 < 0) || (y0 < 0) || + (x1 > pfd->mBounds.width) || (y1 > pfd->mBounds.height)) { + newState |= NS_FRAME_OUTSIDE_CHILDREN; + } + if (newState != oldState) { + frame->SetFrameState(newState); + } + } +} + +void +nsLineLayout::ForgetWordFrame(nsIFrame* aFrame) +{ + NS_ASSERTION((void*)aFrame == mWordFrames[0], "forget-word-frame"); + if (0 != mWordFrames.Count()) { + mWordFrames.RemoveElementAt(0); } - return nsnull; } nsIFrame* @@ -164,56 +1810,41 @@ nsLineLayout::FindNextText(nsIFrame* aFrame) return nsnull; } -PRBool -nsLineLayout::IsNextWordFrame(nsIFrame* aFrame) +nsresult +nsLineLayout::AddText(nsIFrame* aTextFrame) { - if (0 != mWordFrames.Count()) { - nsIFrame* next = (nsIFrame*) mWordFrames[0]; - return next == aFrame; + if (nsnull == mNewTextRun) { + mNewTextRun = new nsTextRun(); + if (nsnull == mNewTextRun) { + return NS_ERROR_OUT_OF_MEMORY; + } + *mTextRunP = mNewTextRun; + mTextRunP = &mNewTextRun->mNext; } - return PR_FALSE; -} - -PRBool -nsLineLayout::IsLastWordFrame(nsIFrame* aFrame) -{ - PRInt32 n = mWordFrames.Count(); - if (0 != n) { - nsIFrame* next = (nsIFrame*) mWordFrames[0]; - return (next == aFrame) && (1 == n); + mNewTextRun->mArray.AppendElement(aTextFrame); +#ifdef DEBUG_ADD_TEXT + PRInt32 n = mNewTextRun->mArray.Count(); + for (PRInt32 i = 0; i < n - 1; i++) { + NS_ASSERTION(mNewTextRun->mArray[i] != (void*)aTextFrame, "yikes"); } - return PR_FALSE; +#endif + return NS_OK;/* XXX */ } void -nsLineLayout::ForgetWordFrame(nsIFrame* aFrame) +nsLineLayout::EndTextRun() { - NS_ASSERTION((void*)aFrame == mWordFrames[0], "forget-word-frame"); - if (0 != mWordFrames.Count()) { - mWordFrames.RemoveElementAt(0); - } + mNewTextRun = nsnull; } -// XXX move this somewhere else!!! -PRBool -nsLineLayout::TreatFrameAsBlock(const nsStyleDisplay* aDisplay, - const nsStylePosition* aPosition) +nsTextRun* +nsLineLayout::TakeTextRuns() { - if (NS_STYLE_POSITION_ABSOLUTE == aPosition->mPosition) { - return PR_FALSE; - } - if (NS_STYLE_FLOAT_NONE != aDisplay->mFloats) { - return PR_FALSE; - } - switch (aDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - case NS_STYLE_DISPLAY_RUN_IN: - case NS_STYLE_DISPLAY_COMPACT: - case NS_STYLE_DISPLAY_TABLE: - return PR_TRUE; - } - return PR_FALSE; + nsTextRun* result = mTextRuns; + mTextRuns = nsnull; + mTextRunP = &mTextRuns; + mNewTextRun = nsnull; + return result; } PRBool @@ -223,24 +1854,19 @@ nsLineLayout::TreatFrameAsBlock(nsIFrame* aFrame) const nsStylePosition* position; aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); aFrame->GetStyleData(eStyleStruct_Position,(const nsStyleStruct*&) position); - return TreatFrameAsBlock(display, position); -} - -void -nsLineLayout::UpdateInlines(nscoord aX, nscoord aY, - nscoord aWidth, nscoord aHeight, - PRBool aIsLeftFloater) -{ - PRInt32 i, n = mInlineStack.Count(); - for (i = 0; i < n; i++) { - nsInlineReflow* ir = (nsInlineReflow*) mInlineStack[i]; - ir->UpdateBand(aX, aY, aWidth, aHeight, aIsLeftFloater); - - // After the first inline is updated the remainder are relative to - // their parent therefore zap the x,y coordinates. - - // XXX border/padding adjustments need to be re-applied for inlines - aX = 0; - aY = 0; + if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { + return PR_FALSE; } + if (NS_STYLE_FLOAT_NONE != display->mFloats) { + return PR_FALSE; + } + switch (display->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + case NS_STYLE_DISPLAY_RUN_IN: + case NS_STYLE_DISPLAY_COMPACT: + case NS_STYLE_DISPLAY_TABLE: + return PR_TRUE; + } + return PR_FALSE; } diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h index 3e16f842d76..1542bcd7dd5 100644 --- a/mozilla/layout/generic/nsLineLayout.h +++ b/mozilla/layout/generic/nsLineLayout.h @@ -19,132 +19,28 @@ #ifndef nsLineLayout_h___ #define nsLineLayout_h___ -#include "nsIFrame.h" +#include "nsFrame.h" #include "nsVoidArray.h" #include "nsTextReflow.h" +class nsISpaceManager; class nsBlockReflowState; -class nsInlineReflow; class nsPlaceholderFrame; -struct nsStyleDisplay; -struct nsStylePosition; -struct nsStyleSpacing; - -// XXX rename to nsLineReflow - -//---------------------------------------------------------------------- +struct nsStyleText; class nsLineLayout { public: nsLineLayout(nsIPresContext& aPresContext, - nsISpaceManager* aSpaceManager); + nsISpaceManager* aSpaceManager, + const nsHTMLReflowState* aOuterReflowState, + PRBool aComputeMaxElementSize); + nsLineLayout(nsIPresContext& aPresContext); ~nsLineLayout(); - void Init(nsBlockReflowState* aReflowState) {/* XXX ctor arg really */ - mBlockReflowState = aReflowState; + void Init(nsBlockReflowState* aState) { + mBlockRS = aState; } - // Prepare this line-layout for the reflow of a new line - void Reset() { - mTotalPlacedFrames = 0; - mColumn = 0; - mEndsInWhiteSpace = PR_TRUE; - mUnderstandsWhiteSpace = PR_FALSE; - mBRFrame = nsnull; - mPlacedFrames.Clear(); - ForgetWordFrames(); - mFirstLetterStyleOK = PR_FALSE; - mPass2VAlignCount = 0; - } - - // Record the prescence of a frame that needs pass2 vertical-align - // handling. - void RecordPass2VAlignFrame() { - mPass2VAlignCount++; - } - - PRBool NeedPass2VAlign() const { - return 0 != mPass2VAlignCount; - } - - // Add to the placed-frame count - void AddPlacedFrame(nsIFrame* aFrame) { - mTotalPlacedFrames++; - mPlacedFrames.AppendElement(aFrame); - } - - // Get the placed-frame count - PRInt32 GetPlacedFrames() const { - return mTotalPlacedFrames; - } - - const nsVoidArray& PlacedFrames() const { - return mPlacedFrames; - } - - void SetBRFrame(nsIFrame* aFrame) { - mBRFrame = aFrame; - } - - nsIFrame* GetBRFrame() const { - return mBRFrame; - } - - void PushInline(nsInlineReflow* aInlineReflow) { - mInlineStack.AppendElement(aInlineReflow); - } - - void PopInline() { - PRInt32 n = mInlineStack.Count(); - if (n > 0) { - mInlineStack.RemoveElementAt(n - 1); - } - } - - void UpdateInlines(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, - PRBool aPlacedLeftFloater); - - // Reset the text-run information in preparation for a FindTextRuns - void ResetTextRuns(); - - // Add another piece of text to a text-run during FindTextRuns. - // Note: continuation frames must NOT add themselves; just the - // first-in-flow - nsresult AddText(nsIFrame* aTextFrame); - - // Close out a text-run during FindTextRuns. - void EndTextRun(); - - // This returns the first nsTextRun found during a - // FindTextRuns. The internal text-run state is reset. - nsTextRun* TakeTextRuns(); - - void SetReflowTextRuns(nsTextRun* aTextRuns) { - mReflowTextRuns = aTextRuns; - } - - nsIFrame* FindNextText(nsIFrame* aFrame); - - nsTextRun* FindTextRunFor(nsIFrame* aFrame); - - void RecordWordFrame(nsIFrame* aWordFrame) { - mWordFrames.AppendElement(aWordFrame); - } - - void ForgetWordFrames() { - mWordFrames.Clear(); - } - - PRBool IsNextWordFrame(nsIFrame* aFrame); - - PRBool InWord() { - return 0 != mWordFrames.Count(); - } - - PRBool IsLastWordFrame(nsIFrame* aFrame); - - void ForgetWordFrame(nsIFrame* aFrame); - PRInt32 GetColumn() { return mColumn; } @@ -153,7 +49,7 @@ public: mColumn = aNewColumn; } - void NextLine() { + void AdvanceToNextLine() { mLineNumber++; } @@ -161,33 +57,63 @@ public: return mLineNumber; } - static PRBool TreatFrameAsBlock(const nsStyleDisplay* aDisplay, - const nsStylePosition* aPosition); + void BeginLineReflow(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aIsTopOfPage); - static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + void EndLineReflow(); - // -------------------------------------------------- + void UpdateBand(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + PRBool aPlacedLeftFloater); - void InitFloater(nsPlaceholderFrame* aFrame); + nsresult BeginSpan(nsIFrame* aFrame, + const nsHTMLReflowState* aSpanReflowState, + nscoord aLeftEdge, + nscoord aRightEdge); - void AddFloater(nsPlaceholderFrame* aFrame); + void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, + nsSize* aMaxElementSize); - nsIPresContext& mPresContext; - nsISpaceManager* mSpaceManager; - nsBlockReflowState* mBlockReflowState; + PRInt32 GetCurrentSpanCount() const; - PRBool mListPositionOutside; - PRInt32 mLineNumber; - PRInt32 mColumn; - - void SetUnderstandsWhiteSpace(PRBool aSetting) { - mUnderstandsWhiteSpace = aSetting; + void SplitLineTo(PRInt32 aNewCount); + + PRBool IsZeroHeight(); + + nsresult ReflowFrame(nsIFrame* aFrame, + nsIFrame** aNextRCFrame, + nsReflowStatus& aReflowStatus); + + + nscoord GetCarriedOutTopMargin() const { + return mCurrentSpan->mLastFrame->mCarriedOutTopMargin; } - PRBool GetUnderstandsWhiteSpace() const { - return mUnderstandsWhiteSpace; + nscoord GetCarriedOutBottomMargin() const { + return mCurrentSpan->mLastFrame->mCarriedOutBottomMargin; } + nsresult AddBulletFrame(nsIFrame* aFrame, + const nsHTMLReflowMetrics& aMetrics); + + void RemoveBulletFrame(nsIFrame* aFrame) { + PushFrame(aFrame); + } + + void VerticalAlignFrames(nsRect& aLineBoxResult, + nsSize& aMaxElementSizeResult); + + void TrimTrailingWhiteSpace(nsRect& aLineBounds); + + void HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify); + + void RelativePositionFrames(nsRect& aCombinedArea); + + //---------------------------------------- + + // Support methods for white-space compression and word-wrapping + // during line reflow + void SetEndsInWhiteSpace(PRBool aState) { mEndsInWhiteSpace = aState; } @@ -196,6 +122,51 @@ public: return mEndsInWhiteSpace; } + void SetUnderstandsWhiteSpace(PRBool aSetting) { + mUnderstandsWhiteSpace = aSetting; + } + + void RecordWordFrame(nsIFrame* aWordFrame) { + mWordFrames.AppendElement(aWordFrame); + } + + PRBool InWord() const { + return 0 != mWordFrames.Count(); + } + + void ForgetWordFrame(nsIFrame* aFrame); + + void ForgetWordFrames() { + mWordFrames.Clear(); + } + + nsIFrame* FindNextText(nsIFrame* aFrame); + + PRBool LineIsEmpty() const { + return 0 == mTotalPlacedFrames; + } + + //---------------------------------------- + + // Inform the line-layout engine about the presence of a BR frame + // XXX get rid of this: use get-frame-type? + void SetBRFrame(nsIFrame* aFrame) { + mBRFrame = aFrame; + } + + // Return the line's BR frame if any + nsIFrame* GetBRFrame() const { + return mBRFrame; + } + + //---------------------------------------- + // Inform the line-layout about the presence of a floating frame + // XXX get rid of this: use get-frame-type? + void InitFloater(nsPlaceholderFrame* aFrame); + void AddFloater(nsPlaceholderFrame* aFrame); + + //---------------------------------------- + PRBool GetFirstLetterStyleOK() const { return mFirstLetterStyleOK; } @@ -204,29 +175,185 @@ public: mFirstLetterStyleOK = aSetting; } -protected: - nsIFrame* mBRFrame; + //---------------------------------------- + // Text run usage methods. These methods are using during reflow to + // track the current text run and to advance through text runs. + void SetReflowTextRuns(nsTextRun* aTextRuns) { + mReflowTextRuns = aTextRuns; + } + + //---------------------------------------- + + static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + + //---------------------------------------- + + // XXX Move this out of line-layout; make some little interface to + // deal with it... + + // Add another piece of text to a text-run during FindTextRuns. + // Note: continuation frames must NOT add themselves; just the + // first-in-flow + nsresult AddText(nsIFrame* aTextFrame); + + // Close out a text-run during FindTextRuns. + void EndTextRun(); + + // This returns the first nsTextRun found during a FindTextRuns. The + // internal text-run state is reset. + nsTextRun* TakeTextRuns(); + + nsIPresContext& mPresContext; + +protected: + // This state is constant for a given block frame doing line layout + nsISpaceManager* mSpaceManager; + const nsStyleText* mStyleText; + const nsHTMLReflowState* mBlockReflowState; + nsBlockReflowState* mBlockRS;/* XXX hack! */ + nscoord mMinLineHeight; + PRBool mComputeMaxElementSize; + PRBool mNoWrap; + PRUint8 mTextAlign; + PRUint8 mDirection; + + // This state varies during the reflow of a line + nsIFrame* mBRFrame; + PRInt32 mLineNumber; + PRInt32 mColumn; PRBool mEndsInWhiteSpace; PRBool mUnderstandsWhiteSpace; PRBool mFirstLetterStyleOK; - PRInt32 mPass2VAlignCount; - + PRBool mIsTopOfPage; + PRBool mWasInWord; + PRBool mCanBreakBeforeFrame; + PRBool mUpdatedBand; + PRUint8 mPlacedFloaters; PRInt32 mTotalPlacedFrames; - nsVoidArray mPlacedFrames; - nsVoidArray mWordFrames; - nsVoidArray mInlineStack; + nscoord mTopEdge; + nscoord mBottomEdge; + nscoord mMaxTopBoxHeight; + nscoord mMaxBottomBoxHeight; - // These slots are used during FindTextRuns + nsTextRun* mReflowTextRuns; + nsTextRun* mTextRun; + + // Per-frame data recorded by the line-layout reflow logic. This + // state is the state needed to post-process the line after reflow + // has completed (vertical alignment, horizontal alignment, + // justification and relative positioning). + struct PerSpanData; + struct PerFrameData { + // link to next/prev frame in same span + PerFrameData* mNext; + PerFrameData* mPrev; + + // pointer to child span data if this is an inline container frame + PerSpanData* mSpan; + + // The frame and its type + nsIFrame* mFrame; + nsCSSFrameType mFrameType; + + // From metrics + nscoord mAscent, mDescent; + nsRect mBounds; + nsSize mMaxElementSize; + nsRect mCombinedArea; + nscoord mCarriedOutTopMargin; + nscoord mCarriedOutBottomMargin; + + // From reflow-state + nsMargin mMargin; + nsMargin mBorderPadding; + nsMargin mOffsets; + PRBool mRelativePos; + + // Other state we use + PRUint8 mVerticalAlign; + }; + PerFrameData mFrameDataBuf[20]; + PerFrameData* mFrameFreeList; + + struct PerSpanData { + PerSpanData* mNext; + PerSpanData* mPrev; + PerSpanData* mParent; + PerFrameData* mFrame; + PerFrameData* mFirstFrame; + PerFrameData* mLastFrame; + + const nsHTMLReflowState* mReflowState; + nscoord mLeftEdge; + nscoord mX; + nscoord mRightEdge; + + nscoord mTopLeading, mBottomLeading; + nscoord mLogicalHeight; + nscoord mMinY, mMaxY; + + void AppendFrame(PerFrameData* pfd) { + if (nsnull == mLastFrame) { + mFirstFrame = pfd; + } + else { + mLastFrame->mNext = pfd; + pfd->mPrev = mLastFrame; + } + mLastFrame = pfd; + } + }; + PerSpanData mSpanDataBuf[20]; + PerSpanData* mSpanFreeList; + PerSpanData* mRootSpan; + PerSpanData* mLastSpan; + PerSpanData* mCurrentSpan; + PRInt32 mSpanDepth; + + // XXX These slots are used ONLY during FindTextRuns nsTextRun* mTextRuns; nsTextRun** mTextRunP; nsTextRun* mNewTextRun; - // These slots are used during InlineReflow - nsTextRun* mReflowTextRuns; - nsTextRun* mTextRun; + nsresult NewPerFrameData(PerFrameData** aResult); + + nsresult NewPerSpanData(PerSpanData** aResult); + + void FreeSpan(PerSpanData* psd); + + PRBool InBlockContext() const { + return mSpanDepth == 0; + } + + void PushFrame(nsIFrame* aFrame); + + void ApplyLeftMargin(PerFrameData* pfd, + nsHTMLReflowState& aReflowState); + + PRBool CanPlaceFrame(PerFrameData* pfd, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); + + void PlaceFrame(PerFrameData* pfd, + nsHTMLReflowMetrics& aMetrics); + + void UpdateFrames(); + + void VerticalAlignFrames(PerSpanData* psd); + + void PlaceTopBottomFrames(PerSpanData* psd, + nscoord aDistanceFromTop, + nscoord aLineHeight); + + void RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea); + +#ifdef DEBUG + void DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent); +#endif }; #endif /* nsLineLayout_h___ */ diff --git a/mozilla/layout/html/base/src/Makefile.in b/mozilla/layout/html/base/src/Makefile.in index 3a042cd9010..054b114c6ec 100644 --- a/mozilla/layout/html/base/src/Makefile.in +++ b/mozilla/layout/html/base/src/Makefile.in @@ -44,7 +44,6 @@ CPPSRCS= \ nsImageFrame.cpp \ nsImageMap.cpp \ nsInlineFrame.cpp \ - nsInlineReflow.cpp \ nsLeafFrame.cpp \ nsLineBox.cpp \ nsLineLayout.cpp \ diff --git a/mozilla/layout/html/base/src/makefile.win b/mozilla/layout/html/base/src/makefile.win index 7f74ad745cf..58b52969139 100644 --- a/mozilla/layout/html/base/src/makefile.win +++ b/mozilla/layout/html/base/src/makefile.win @@ -44,7 +44,6 @@ CPPSRCS= \ nsImageFrame.cpp \ nsImageMap.cpp \ nsInlineFrame.cpp \ - nsInlineReflow.cpp \ nsLeafFrame.cpp \ nsLineBox.cpp \ nsLineLayout.cpp \ @@ -81,7 +80,6 @@ CPP_OBJS= \ .\$(OBJDIR)\nsImageFrame.obj \ .\$(OBJDIR)\nsImageMap.obj \ .\$(OBJDIR)\nsInlineFrame.obj \ - .\$(OBJDIR)\nsInlineReflow.obj \ .\$(OBJDIR)\nsLeafFrame.obj \ .\$(OBJDIR)\nsLineBox.obj \ .\$(OBJDIR)\nsLineLayout.obj \ diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h index dd9ca8b5067..0ea613b8178 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -277,8 +277,6 @@ protected: nsLineBox* aLine, nscoord aDeltaY); - void TakeRunInFrames(nsBlockFrame* aRunInFrame); - nsresult ComputeTextRuns(nsIPresContext& aPresContext); void BuildFloaterList(); diff --git a/mozilla/layout/html/base/src/nsBlockReflowContext.cpp b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp index 5ccb35f8d69..ac11c762211 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowContext.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowContext.cpp @@ -38,7 +38,6 @@ nsBlockReflowContext::nsBlockReflowContext(nsIPresContext& aPresContext, mOuterReflowState(aParentRS), mMetrics(aComputeMaxElementSize ? &mMaxElementSize : nsnull) { - mRunInFrame = nsnull; mCompactMarginWidth = 0; mStyleSpacing = nsnull; } @@ -102,7 +101,6 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame, availSpace, reason); aComputedOffsets = reflowState.computedOffsets; reflowState.lineLayout = nsnull; - reflowState.mRunInFrame = mRunInFrame; reflowState.mCompactMarginWidth = mCompactMarginWidth; if (!aIsAdjacentWithTop) { reflowState.isTopOfPage = PR_FALSE; // make sure this is cleared @@ -312,6 +310,8 @@ nsBlockReflowContext::PlaceBlock(PRBool aForceFit, mFrame->SetRect(r); aInFlowBounds = r; aCombinedRect = mMetrics.mCombinedArea; + mTopMargin = 0; + mBottomMargin = 0; fits = PR_TRUE; } else { diff --git a/mozilla/layout/html/base/src/nsBlockReflowContext.h b/mozilla/layout/html/base/src/nsBlockReflowContext.h index b3104e91802..f8835ddc398 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowContext.h +++ b/mozilla/layout/html/base/src/nsBlockReflowContext.h @@ -40,10 +40,6 @@ public: PRBool aComputeMaxElementSize); ~nsBlockReflowContext() { } - void SetRunInFrame(nsBlockFrame* aRunInFrame) { - mRunInFrame = aRunInFrame; - } - void SetCompactMarginWidth(nscoord aCompactMarginWidth) { mCompactMarginWidth = aCompactMarginWidth; } @@ -132,7 +128,6 @@ protected: const nsHTMLReflowState& mOuterReflowState; nsIFrame* mFrame; - nsBlockFrame* mRunInFrame; nscoord mCompactMarginWidth; nsRect mSpace; nsIFrame* mNextRCFrame; diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index ac46b59140a..017a7055e5b 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -23,7 +23,6 @@ #include "nsLineBox.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsPlaceholderFrame.h" #include "nsStyleConsts.h" #include "nsHTMLIIDs.h" @@ -64,7 +63,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -75,7 +73,6 @@ static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);/* XXX */ #undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE -#undef NOISY_RUNIN #undef NOISY_FLOATER_CLEARING #undef NOISY_INCREMENTAL_REFLOW #undef REFLOW_STATUS_COVERAGE @@ -210,7 +207,6 @@ public: const nsHTMLReflowState& mReflowState; nsLineLayout* mLineLayout; - nsInlineReflow* mInlineReflow; nsISpaceManager* mSpaceManager; nscoord mSpaceManagerX, mSpaceManagerY; @@ -219,9 +215,6 @@ public: nsReflowStatus mReflowStatus; - nsBlockFrame* mRunInFromFrame; - nsBlockFrame* mRunInToFrame; - nscoord mBottomEdge; // maximum Y PRBool mUnconstrainedWidth; @@ -275,12 +268,12 @@ public: void nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->InitFloater(aFrame); + mBlockRS->InitFloater(aFrame); } void nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame) { - mBlockReflowState->AddFloater(aFrame, PR_FALSE); + mBlockRS->AddFloater(aFrame, PR_FALSE); } //---------------------------------------------------------------------- @@ -298,8 +291,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mIsMarginRoot(PR_FALSE), mCarriedOutTopMargin(0) { - mInlineReflow = nsnull; - mLineLayout = aLineLayout; mSpaceManager = aReflowState.spaceManager; @@ -316,30 +307,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow); mKidXMost = 0; - mRunInFromFrame = nsnull; - mRunInToFrame = nsnull; - -#if 0 - // Compute "content area" - mUnconstrainedWidth = aReflowState.computedWidth == NS_UNCONSTRAINEDSIZE; - mUnconstrainedHeight = aReflowState.computedHeight == NS_UNCONSTRAINEDSIZE; -#ifdef NS_DEBUG - if ((!mUnconstrainedWidth && (aReflowState.computedWidth > 200000)) || - (!mUnconstrainedHeight && (aReflowState.computedHeight > 200000))) { - mBlock->ListTag(stdout); - 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 (aReflowState.computedHeight > 200000) { - mUnconstrainedHeight = PR_TRUE; - } - } -#endif -#endif - // Compute content area width (the content area is inside the border // and padding) mUnconstrainedWidth = PR_FALSE; @@ -893,30 +860,14 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - // Replace parent provided reflow state with our own significantly - // more extensive version. - nsLineLayout ll(aPresContext, aReflowState.spaceManager); - nsLineLayout* lineLayout = ≪ + nsLineLayout lineLayout(aPresContext, aReflowState.spaceManager, + &aReflowState, nsnull != aMetrics.maxElementSize); nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, - lineLayout); + &lineLayout); + lineLayout.Init(&state); if (NS_BLOCK_MARGIN_ROOT & mFlags) { state.mIsMarginRoot = PR_TRUE; } - lineLayout->Init(&state); - - // Prepare inline-reflow engine. Note that we will almost always use - // 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(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 = nsHTMLReflowState::CalcLineHeight(aPresContext, this); - inlineReflow.SetMinLineHeight(minLineHeight); if (eReflowReason_Resize != aReflowState.reason) { RenumberLists(); @@ -956,7 +907,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, else { // Get next frame in reflow command chain aReflowState.reflowCommand->GetNext(state.mNextRCFrame); - inlineReflow.SetNextRCFrame(state.mNextRCFrame); // Now do the reflow rv = PrepareChildIncrementalReflow(state); @@ -989,7 +939,6 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext, // Compute our final size ComputeFinalSize(aReflowState, state, aMetrics); - lineLayout->PopInline(); #ifdef NOISY_FINAL_SIZE ListTag(stdout); @@ -1044,6 +993,20 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.right; computedWidth = maxWidth; } + else if (aState.mComputeMaxElementSize) { + // See if our max-element-size width is larger than our + // computed-width. This happens when we are impacted by a + // floater. When this does happen, our desired size needs to + // include room for the floater. + if (computedWidth < aMetrics.maxElementSize->width) { +#ifdef DEBUG_kipp + ListTag(stdout); + printf(": adjusting width from %d to %d\n", computedWidth, + aMetrics.maxElementSize->width); +#endif + computedWidth = aMetrics.maxElementSize->width; + } + } aMetrics.width = computedWidth; } #ifdef DEBUG_kipp @@ -1093,6 +1056,8 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, (0 == aState.mY - borderPadding.top))) { aMetrics.width = 0; aMetrics.height = 0; + aMetrics.mCarriedOutTopMargin = 0; + aMetrics.mCarriedOutBottomMargin = 0; emptyFrame = PR_TRUE; } @@ -1218,17 +1183,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, nsresult nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) { - if ((nsnull == mPrevInFlow) && (nsnull != aState.mReflowState.mRunInFrame)) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": run-in from: "); - aState.mReflowState.mRunInFrame->ListTag(stdout); - printf("\n"); -#endif - // Take frames away from the run-in frame - TakeRunInFrames(aState.mReflowState.mRunInFrame); - } - PrepareResizeReflow(aState); return NS_OK; } @@ -1598,7 +1552,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } // Pull data from a next-in-flow if we can @@ -1663,7 +1617,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) // If this is an inline frame then its time to stop aState.mPrevLine = line; line = line->mNext; - aState.mLineLayout->NextLine(); + aState.mLineLayout->AdvanceToNextLine(); } } @@ -1719,8 +1673,8 @@ nsBlockFrame::WillReflowLine(nsBlockReflowState& aState, */ nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, - nsLineBox* aLine, - PRBool* aKeepReflowGoing) + nsLineBox* aLine, + PRBool* aKeepReflowGoing) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBlockFrame::ReflowLine: line=%p", aLine)); @@ -1748,7 +1702,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, } // Setup the line-layout for the new line - aState.mLineLayout->Reset(); aState.mCurrentLine = aLine; aLine->ClearDirty(); aLine->SetNeedDidReflow(); @@ -1758,37 +1711,22 @@ 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 -#endif - { - // Notify observers that we are about to reflow the line - WillReflowLine(aState, aLine); + // Notify observers that we are about to reflow the line + WillReflowLine(aState, aLine); - rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + if (NS_FAILED(rv)) { + return rv; } } else { - // When this class is an inline frame and we are reflowing inline - // frames then there is no point in getting available space. - nscoord x, availWidth, availHeight; - aState.GetAvailableSpace(); - // Setup initial coordinate system for reflowing the inline frames // into. + aState.GetAvailableSpace(); const nsMargin& borderPadding = aState.BorderPadding(); - x = aState.mAvailSpaceRect.x + borderPadding.left; - availWidth = aState.mAvailSpaceRect.width; - + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; if (aState.mUnconstrainedHeight) { availHeight = NS_UNCONSTRAINEDSIZE; } @@ -1796,7 +1734,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, /* XXX get the height right! */ availHeight = aState.mAvailSpaceRect.height; } - aState.mInlineReflow->Init(x, aState.mY, availWidth, availHeight); + nsLineLayout* lineLayout = aState.mLineLayout; + lineLayout->BeginLineReflow(x, aState.mY, availWidth, availHeight, + PR_FALSE /*XXX isTopOfPage*/); // Notify observers that we are about to reflow the line WillReflowLine(aState, aLine); @@ -1863,6 +1803,9 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { rv = PlaceLine(aState, aLine, aKeepReflowGoing); } + else { + lineLayout->EndLineReflow(); + } } return rv; @@ -2192,14 +2135,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) nextFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) { -#ifdef NOISY_RUNIN - ListTag(stdout); - printf(": frame: "); - nsFrame::ListTag(stdout, aFrame); - printf(" followed by: "); - nsFrame::ListTag(stdout, nextFrame); - printf("\n"); -#endif followingBlockFrame = (nsBlockFrame*) nextFrame; break; } @@ -2217,30 +2152,6 @@ nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame) return followingBlockFrame; } -#if XXX -void -nsBlockFrame::WillReflowFrame(nsBlockReflowState& aState, - nsLineBox* aLine, - nsIFrame* aFrame) -{ - nsIStyleContext* kidSC; - aFrame->GetStyleContext(kidSC); - if (nsnull != kidSC) { - nsIStyleContext* kidParentSC; - kidParentSC = kidSC->GetParent(); - if (nsnull != kidParentSC) { - if (kidParentSC != mStyleContext) { - // The frame has changed situations so re-resolve its style - // context in the new situation. - aFrame->ReResolveStyleContext(&aState.mPresContext, mStyleContext); - } - NS_RELEASE(kidParentSC); - } - NS_RELEASE(kidSC); - } -} -#endif - // XXX This should be a no-op when there is no first-line/letter style // in force! void @@ -2305,15 +2216,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, PRBool* aKeepReflowGoing) { NS_PRECONDITION(*aKeepReflowGoing, "bad caller"); - NS_PRECONDITION(0 == aState.mLineLayout->GetPlacedFrames(), - "non-empty line with a block"); nsresult rv = NS_OK; nsIFrame* frame = aLine->mFirstChild; // Prepare the inline reflow engine -//XXX nsBlockFrame* runInToFrame; nsBlockFrame* compactWithFrame; nscoord compactMarginWidth = 0; PRBool isCompactFrame = PR_FALSE; @@ -2321,38 +2229,6 @@ 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); - printf(": trying to see if "); - aFrame->ListTag(stdout); - printf(" is a run-in candidate\n"); -#endif - runInToFrame = FindFollowingBlockFrame(frame); - if (nsnull != runInToFrame) { -// XXX run-in frame should be pushed to the next-in-flow too if the -// run-in-to frame is pushed. - nsRect r(0, aState.mY, 0, 0); - aLine->mBounds = r; - aLine->mCombinedArea = r; - aLine->mCarriedOutTopMargin = 0; - aLine->mCarriedOutBottomMargin = 0; - aLine->SetMarginFlags(0); -#if XXX_need_line_outside_children - aLine->ClearOutsideChildren(); -#endif - aLine->mBreakType = NS_STYLE_CLEAR_NONE; -//XXX aFrame->WillReflow(aState.mPresContext); - frame->SetRect(r); - aState.mPrevChild = frame; - aState.mRunInToFrame = runInToFrame; - aState.mRunInFrame = (nsBlockFrame*) frame; - return rv; - } - break; -#endif - case NS_STYLE_DISPLAY_COMPACT: compactWithFrame = FindFollowingBlockFrame(frame); if (nsnull != compactWithFrame) { @@ -2392,15 +2268,6 @@ 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 ? NS_UNCONSTRAINEDSIZE @@ -2655,9 +2522,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, PRBool reflowingFirstLetter = aState.mLineLayout->GetFirstLetterStyleOK(); // Reflow the inline frame + nsLineLayout* lineLayout = aState.mLineLayout; nsReflowStatus frameReflowStatus; - nsresult rv = aState.mInlineReflow->ReflowFrame(aFrame, aState.IsAdjacentWithTop(), - frameReflowStatus); + nsresult rv = lineLayout->ReflowFrame(aFrame, &aState.mNextRCFrame, + frameReflowStatus); if (NS_FAILED(rv)) { return rv; } @@ -2822,8 +2690,8 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, nsLineBox* aLine, nsIFrame* aFrame) { - PRInt32 pushCount = aLine->ChildCount() - - aState.mInlineReflow->GetCurrentFrameNum(); + nsLineLayout* lineLayout = aState.mLineLayout; + PRInt32 pushCount = aLine->ChildCount() - lineLayout->GetCurrentSpanCount(); //printf("BEFORE (pushCount=%d):\n", pushCount); //aLine->List(stdout, 0); if (0 != pushCount) { @@ -2858,10 +2726,10 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState, to->SetIsBlock(aLine->IsBlock()); aLine->mChildCount -= pushCount; - // Let inline reflow know that some frames are no longer part of - // its state. + // Let line layout know that some frames are no longer part of its + // state. if (!aLine->IsBlock()) { - aState.mInlineReflow->ChangeFrameCount(aLine->ChildCount()); + lineLayout->SplitLineTo(aLine->ChildCount()); } #ifdef DEBUG VerifyFrameCount(mLines); @@ -2927,18 +2795,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // method is used for placing a line of inline frames. If the rare // case is happening then the worst that will happen is that the // bullet frame will be reflowed twice. - nsInlineReflow& ir = *aState.mInlineReflow; + nsLineLayout* lineLayout = aState.mLineLayout; PRBool addedBullet = PR_FALSE; - if (HaveOutsideBullet() && (aLine == mLines) && !ir.IsZeroHeight()) { + if (HaveOutsideBullet() && (aLine == mLines) && + !lineLayout->IsZeroHeight()) { nsHTMLReflowMetrics metrics(nsnull); ReflowBullet(aState, metrics); - ir.AddFrame(mBullet, metrics); + lineLayout->AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord a, d; - ir.VerticalAlignFrames(aLine->mBounds, a, d); + nsSize maxElementSize; + lineLayout->VerticalAlignFrames(aLine->mBounds, maxElementSize); if (addedBullet) { - ir.RemoveFrame(mBullet); + lineLayout->RemoveBulletFrame(mBullet); } #ifdef DEBUG_kipp NS_ASSERTION((aLine->mBounds.YMost()) < 200000 && (aLine->mBounds.y > -200000), "oy"); @@ -2955,14 +2824,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, #else PRBool allowJustify = PR_FALSE; #endif - ir.TrimTrailingWhiteSpace(aLine->mBounds); - ir.HorizontalAlignFrames(aLine->mBounds, allowJustify); - ir.RelativePositionFrames(aLine->mCombinedArea); + lineLayout->TrimTrailingWhiteSpace(aLine->mBounds); + lineLayout->HorizontalAlignFrames(aLine->mBounds, allowJustify); + lineLayout->RelativePositionFrames(aLine->mCombinedArea); // Calculate the bottom margin for the line. nscoord lineBottomMargin = 0; if (0 == aLine->mBounds.height) { - nsIFrame* brFrame = aState.mLineLayout->GetBRFrame(); + // XXX I don't think that this is necessary anymore because of the + // way that min-line-height is applied in the vertical alignment + // code; since we always have a line-height, a BR on its own line + // will get at least the default line-height amount of vertical + // space. + nsIFrame* brFrame = lineLayout->GetBRFrame(); if (nsnull != brFrame) { // If a line ends in a BR, and the line is empty of height, then // we make sure that the line ends up with some height @@ -2984,43 +2858,32 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, } } } - else { - aState.mRunInFromFrame = nsnull; - aState.mRunInToFrame = nsnull; - } // Calculate the lines top and bottom margin values. The margin will // come from an embedded block frame, not from inline // frames. Because this is an "inline" line, the child margins are // all effectively zero so we pass in nsMargin(0, 0, 0, 0). nscoord topMargin, bottomMargin; + nscoord cotm = lineLayout->GetCarriedOutTopMargin(); + nscoord cobm = lineLayout->GetCarriedOutBottomMargin(); nsBlockReflowContext::CollapseMargins(nsMargin(0, 0, 0, 0), - ir.GetCarriedOutTopMargin(), - ir.GetCarriedOutBottomMargin(), + cotm, cobm, aLine->mBounds.height, aState.mPrevBottomMargin, topMargin, bottomMargin); -#if XXX -ListTag(stdout); -printf(": "); -((nsFrame*)(aLine->mFirstChild))->ListTag(stdout); -printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", - aState.mY, ir.GetCarriedOutTopMargin(), ir.GetCarriedOutBottomMargin(), - topMargin, bottomMargin, aState.mPrevBottomMargin, - aState.ShouldApplyTopMargin() ? "yes" : "no"); -#endif if (!aState.ShouldApplyTopMargin()) { aState.mCarriedOutTopMargin = topMargin; topMargin = 0; } + lineLayout->EndLineReflow(); +#ifdef DEBUG + lineLayout = nsnull; +#endif // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. nscoord newY = aLine->mBounds.YMost() + topMargin + lineBottomMargin; - NS_FRAME_TRACE(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::PlaceLine: newY=%d limit=%d lineHeight=%d", - newY, aState.mBottomEdge, aLine->mBounds.height)); if ((mLines != aLine) && (newY > aState.mBottomEdge)) { // Push this line and all of it's children and anything else that // follows to our next-in-flow @@ -3037,8 +2900,8 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", return rv; } - aLine->mCarriedOutTopMargin = ir.GetCarriedOutTopMargin(); - aLine->mCarriedOutBottomMargin = ir.GetCarriedOutBottomMargin(); + aLine->mCarriedOutTopMargin = cotm; + aLine->mCarriedOutBottomMargin = cobm; aState.mPrevBottomMargin = bottomMargin; if (0 != topMargin) { // Apply collapsed top-margin value @@ -3048,7 +2911,7 @@ printf(" mY=%d carried=%d,%d top=%d bottom=%d prev=%d shouldApply=%s\n", } aState.mY = newY; - PostPlaceLine(aState, aLine, ir.GetMaxElementSize()); + PostPlaceLine(aState, aLine, maxElementSize); // Any below current line floaters to place? if (0 != aState.mPendingFloaters.Count()) { @@ -3094,8 +2957,8 @@ nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState, void nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - const nsSize& aMaxElementSize) + nsLineBox* aLine, + const nsSize& aMaxElementSize) { // Update max-element-size if (aState.mComputeMaxElementSize) { @@ -3355,7 +3218,6 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, if (nsnull != lastFrame) { lastFrame->SetNextSibling(aNewFrame); } - nsresult rv; // Make sure that new inlines go onto the end of the lastLine when // the lastLine is mapping inline frames. @@ -3371,19 +3233,7 @@ nsBlockFrame::AppendNewFrames(nsIPresContext& aPresContext, for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(&frame)) { // See if the child is a block or non-block - const nsStyleDisplay* kidDisplay; - rv = frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) kidDisplay); - if (NS_OK != rv) { - return rv; - } - const nsStylePosition* kidPosition; - rv = frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) kidPosition); - if (NS_OK != rv) { - return rv; - } - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(frame); // If the child is an inline then add it to the lastLine (if it's // an inline line, otherwise make a new line). If the child is a @@ -3517,15 +3367,8 @@ nsBlockFrame::InsertNewFrames(nsIPresContext& aPresContext, nsIFrame* next; newFrame->GetNextSibling(&next); newFrame->SetNextSibling(nsnull); - - const nsStyleDisplay* display; - newFrame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - newFrame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); PRUint16 newFrameIsBlock = - nsLineLayout::TreatFrameAsBlock(display, position) + nsLineLayout::TreatFrameAsBlock(newFrame) ? LINE_IS_BLOCK : 0; @@ -4092,7 +3935,7 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Now place the floater immediately if possible. Otherwise stash it // away in mPendingFloaters and place it later. - if (0 == mLineLayout->GetPlacedFrames()) { + if (mLineLayout->LineIsEmpty()) { NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, ("nsBlockReflowState::AddFloater: IsLeftMostChild, placeHolder=%p", aPlaceholder)); @@ -4118,11 +3961,11 @@ nsBlockReflowState::AddFloater(nsPlaceholderFrame* aPlaceholder, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(); - mLineLayout->UpdateInlines(mAvailSpaceRect.x + BorderPadding().left, - mY, - mAvailSpaceRect.width, - mAvailSpaceRect.height, - isLeftFloater); + mLineLayout->UpdateBand(mAvailSpaceRect.x + BorderPadding().left, + mY, + mAvailSpaceRect.width, + mAvailSpaceRect.height, + isLeftFloater); // Restore coordinate system mSpaceManager->Translate(dx, dy); @@ -4797,9 +4640,9 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; - nsLineLayout textRunThingy(aPresContext, nsnull); + nsLineLayout textRunThingy(aPresContext); - // Ask each child that implements nsIInlineReflow to find its text runs + // Ask each child to find its text runs nsLineBox* line = mLines; while (nsnull != line) { if (!line->IsBlock()) { @@ -4822,8 +4665,8 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) } } else { - // A frame that doesn't implement nsIInlineReflow isn't text - // therefore it will end an open text run. + // A block frame isn't text therefore it will end an open text + // run. textRunThingy.EndTextRun(); } line = line->mNext; @@ -4835,39 +4678,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext& aPresContext) return NS_OK; } -void -nsBlockFrame::TakeRunInFrames(nsBlockFrame* aRunInFrame) -{ - // Simply steal the run-in-frame's line list and make it our - // own. XXX Very similar to the logic in DrainOverflowLines... - nsLineBox* line = aRunInFrame->mLines; - - // Make all the frames on the mOverflowLines list mine - nsIFrame* lastFrame = nsnull; - nsIFrame* frame = line->mFirstChild; - while (nsnull != frame) { - frame->SetParent(this); - lastFrame = frame; - frame->GetNextSibling(&frame); - } - - // Join the line lists - if (nsnull == mLines) { - mLines = line; - } - else { - // Join the sibling lists together - lastFrame->SetNextSibling(mLines->mFirstChild); - - // Place overflow lines at the front of our line list - nsLineBox* lastLine = nsLineBox::LastLine(line); - lastLine->mNext = mLines; - mLines = line; - } - - aRunInFrame->mLines = nsnull; -} - //---------------------------------------------------------------------- nsresult @@ -5065,29 +4875,6 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) #endif } -#if 0 -nscoord -nsBlockFrame::ComputeCollapsedTopMargin(const nsHTMLReflowState& aReflowState) -{ - nscoord myTopMargin = aReflowState.computedMargin.top; - nsLineBox* line = mLines; - if (nsnull != line) { - if (line->IsEmptyLine()) { - line = line->mNext; - if (nsnull == line) { - return myTopMargin; - } - } - if (1 == line->ChildCount()) { - nsHTMLReflowState rs(); - nscoord topMargin = line->mFirstChild->ComputeCollapsedTopMargin(rs); - return nsBlockReflowContext::MaxMargin(topMargin, myTopMargin); - } - } - return myTopMargin; -} -#endif - #ifdef DEBUG void nsBlockFrame::VerifyFrameCount(nsLineBox* line) diff --git a/mozilla/layout/html/base/src/nsBulletFrame.cpp b/mozilla/layout/html/base/src/nsBulletFrame.cpp index 6556ddb693a..23e1ae86183 100644 --- a/mozilla/layout/html/base/src/nsBulletFrame.cpp +++ b/mozilla/layout/html/base/src/nsBulletFrame.cpp @@ -71,6 +71,7 @@ nsBulletFrame::Paint(nsIPresContext& aCX, if (disp->mVisible) { const nsStyleList* myList = (const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List); + PRUint8 listStyleType = myList->mListStyleType; if (myList->mListStyleImage.Length() > 0) { nsIImage* image = mImageLoader.GetImage(); @@ -81,11 +82,14 @@ nsBulletFrame::Paint(nsIPresContext& aCX, } } else { - nsRect innerArea(mPadding.left, mPadding.top, - mRect.width - (mPadding.left + mPadding.right), - mRect.height - (mPadding.top + mPadding.bottom)); - aRenderingContext.DrawImage(image, innerArea); - return NS_OK; + if (!mImageLoader.GetLoadImageFailed()) { + nsRect innerArea(mPadding.left, mPadding.top, + mRect.width - (mPadding.left + mPadding.right), + mRect.height - (mPadding.top + mPadding.bottom)); + aRenderingContext.DrawImage(image, innerArea); + return NS_OK; + } + listStyleType = NS_STYLE_LIST_STYLE_DISC; } } @@ -98,7 +102,7 @@ nsBulletFrame::Paint(nsIPresContext& aCX, aRenderingContext.SetColor(myColor->mColor); nsAutoString text; - switch (myList->mListStyleType) { + switch (listStyleType) { case NS_STYLE_LIST_STYLE_NONE: break; diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 346e7a44e47..c539e0fa6f4 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -1048,17 +1048,6 @@ nsFrame::MoveInSpaceManager(nsIPresContext& aPresContext, return NS_OK; } -NS_IMETHODIMP -nsFrame::VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedRect) -{ - aCombinedRect = mRect; - return NS_OK; -} - NS_IMETHODIMP nsFrame::ContentChanged(nsIPresContext* aPresContext, nsIContent* aChild, diff --git a/mozilla/layout/html/base/src/nsFrame.h b/mozilla/layout/html/base/src/nsFrame.h index e2e93645efb..7bf0d2a163a 100644 --- a/mozilla/layout/html/base/src/nsFrame.h +++ b/mozilla/layout/html/base/src/nsFrame.h @@ -234,11 +234,6 @@ public: NS_IMETHOD MoveInSpaceManager(nsIPresContext& aPresContext, nsISpaceManager* aSpaceManager, nscoord aDeltaX, nscoord aDeltaY); - NS_IMETHOD VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedRect); // Selection Methods // XXX Doc me... (in nsIFrame.h puhleeze) diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp index 25e4695569b..66e78923f61 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -115,7 +115,7 @@ nsHTMLContainerFrame::CreateNextInFlow(nsIPresContext& aPresContext, nextInFlow->SetNextSibling(nextFrame); NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES, - ("nsInlineReflow::MaybeCreateNextInFlow: frame=%p nextInFlow=%p", + ("nsHTMLContainerFrame::MaybeCreateNextInFlow: frame=%p nextInFlow=%p", aFrame, nextInFlow)); aNextInFlowResult = nextInFlow; diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index 66732bed96f..568cf6534a7 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -126,7 +126,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext& aPresContext, void nsHTMLReflowState::Init(nsIPresContext& aPresContext) { - mRunInFrame = nsnull; mCompactMarginWidth = 0; mAlignCharOffset = 0; mUseAlignCharOffset = 0; @@ -1119,25 +1118,23 @@ nsHTMLReflowState::CalcLineHeight(nsIPresContext& aPresContext, sc->GetStyleData(eStyleStruct_Text); if (nsnull != text) { nsStyleUnit unit = text->mLineHeight.GetUnit(); - if (eStyleUnit_Enumerated == unit) { - // Normal value; we use 1.0 for normal - // XXX could come from somewhere else + if (eStyleUnit_Normal == unit) { + // Normal value; we use a factor of 1.0 for normal + lineHeight = elementFont->mFont.size; #ifdef NOISY_VERTICAL_ALIGN - printf(" line-height: normal\n"); + printf(" line-height: normal result=%d\n", lineHeight); #endif break; } else if (eStyleUnit_Factor == unit) { - if (nsnull != elementFont) { - // CSS2 spec says that the number is inherited, not the - // computed value. Therefore use the font size of the - // element times the inherited number. - nscoord size = elementFont->mFont.size; - lineHeight = nscoord(size * text->mLineHeight.GetFactorValue()); + // CSS2 spec says that the number is inherited, not the + // computed value. Therefore use the font size of the + // element times the inherited number. + nscoord size = elementFont->mFont.size; + lineHeight = nscoord(size * text->mLineHeight.GetFactorValue()); #ifdef NOISY_VERTICAL_ALIGN - printf(" line-height: factor=%g result=%d\n", - text->mLineHeight.GetFactorValue(), lineHeight); + printf(" line-height: factor=%g result=%d\n", + text->mLineHeight.GetFactorValue(), lineHeight); #endif - } break; } else if (eStyleUnit_Coord == unit) { diff --git a/mozilla/layout/html/base/src/nsIHTMLReflow.h b/mozilla/layout/html/base/src/nsIHTMLReflow.h index 00e1ff5e5f4..d7603b8a2c8 100644 --- a/mozilla/layout/html/base/src/nsIHTMLReflow.h +++ b/mozilla/layout/html/base/src/nsIHTMLReflow.h @@ -171,9 +171,6 @@ struct nsHTMLReflowState : nsReflowState { nscoord mComputedMinWidth, mComputedMaxWidth; nscoord mComputedMinHeight, mComputedMaxHeight; - // Run-in frame made available for reflow - nsBlockFrame* mRunInFrame; - // Compact margin available space nscoord mCompactMarginWidth; @@ -428,16 +425,6 @@ public: NS_IMETHOD MoveInSpaceManager(nsIPresContext& aPresContext, nsISpaceManager* aSpaceManager, nscoord aDeltaX, nscoord aDeltaY) = 0; - - NS_IMETHOD VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aReflowState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedRect) = 0; - -#if 0 - NS_IMETHOD RelativePositionFrames(nsRect& aCombinedArea) = 0; -#endif }; #endif /* nsIHTMLReflow_h___ */ diff --git a/mozilla/layout/html/base/src/nsImageMap.cpp b/mozilla/layout/html/base/src/nsImageMap.cpp index 4f794005e40..31850c74fd0 100644 --- a/mozilla/layout/html/base/src/nsImageMap.cpp +++ b/mozilla/layout/html/base/src/nsImageMap.cpp @@ -77,8 +77,8 @@ public: nsString mAltText; nscoord* mCoords; PRInt32 mNumCoords; - PRBool mHasURL; PRBool mSuppressFeedback; + PRBool mHasURL; }; Area::Area(const nsString& aBaseURL, const nsString& aHREF, @@ -753,7 +753,7 @@ nsImageMap::UpdateAreas() // Get rid of old area data FreeAreas(); - nsresult rv; + nsresult rv = NS_OK; nsIContent* child; PRInt32 i, n; PRBool containsBlock = PR_FALSE, containsArea = PR_FALSE; diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index aa3fb212cc7..67e433c8bd6 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -20,7 +20,6 @@ #include "nsFrameList.h" #include "nsBlockReflowContext.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" @@ -28,6 +27,8 @@ #include "nsIStyleContext.h" #include "nsIPresShell.h" #include "nsIPresContext.h" +#include "nsIRenderingContext.h" +#include "nsIFontMetrics.h" // XXX TODO: // append/insert/remove floater testing @@ -35,7 +36,7 @@ // Theory of operation: // XXX write this -#ifdef NS_DEBUG +#ifdef DEBUG #undef NOISY_ANON_BLOCK #else #undef NOISY_ANON_BLOCK @@ -89,17 +90,11 @@ public: nsIRenderingContext& aRC, nscoord& aDeltaWidth); #endif - NS_IMETHOD VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aParentReflowState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedArea); protected: // Additional reflow state used during our reflow methods struct InlineReflowState { nsIFrame* mNextRCFrame; - nsInlineReflow* mInlineReflow; nsIFrame* mPrevFrame; nsInlineFrame* mNextInFlow; }; @@ -1184,13 +1179,15 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { + if (nsnull == aReflowState.lineLayout) { + return NS_ERROR_INVALID_ARG; + } DrainOverflow(); // Set our own reflow state (additional state above and beyond // aReflowState) InlineReflowState irs; irs.mPrevFrame = nsnull; - irs.mInlineReflow = nsnull; irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; if (eReflowReason_Incremental == aReflowState.reason) { // Peel off the next frame in the path if this is an incremental @@ -1228,8 +1225,7 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, } if (HaveAnonymousBlock()) { - if ((nsnull != aReflowState.lineLayout) && - (0 != aReflowState.lineLayout->GetPlacedFrames())) { + if (!aReflowState.lineLayout->LineIsEmpty()) { // This inline frame cannot be placed on the current line // because there already is an inline frame on this line (and we // contain an anonymous block). @@ -1239,30 +1235,27 @@ nsInlineFrame::Reflow(nsIPresContext& aPresContext, else { rv = ReflowBlockFrame(aPresContext, aReflowState, irs, aMetrics, aStatus); + + // If the combined area of our children exceeds our bounding box + // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear + // it. + if ((aMetrics.mCombinedArea.x < 0) || + (aMetrics.mCombinedArea.y < 0) || + (aMetrics.mCombinedArea.XMost() > aMetrics.width) || + (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } + else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } } } else { - if (nsnull != aReflowState.lineLayout) { - rv = ReflowInlineFrames(aPresContext, aReflowState, irs, - aMetrics, aStatus); - } - else { - rv = NS_ERROR_NULL_POINTER; - } - } - - if (NS_SUCCEEDED(rv)) { - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } + rv = ReflowInlineFrames(aPresContext, aReflowState, irs, + aMetrics, aStatus); + // Note: when we are reflowing inline frames the line layout code + // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for + // us. } return rv; @@ -1288,114 +1281,6 @@ nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) return NS_OK; } -// Perform pass2 vertical alignment on top/bottom aligned child frames -// XXX relative positioning will need to be done *after* this -NS_IMETHODIMP -nsInlineFrame::VerticalAlignFrames(nsIPresContext& aPresContext, - const nsHTMLReflowState& aParentReflowState, - nscoord aLineHeight, - nscoord aDistanceFromTopEdge, - nsRect& aCombinedArea) -{ - if (HaveAnonymousBlock()) { - // This should be impossible - when we have an inline frame and it - // contains an anonymous block, none of the blocks children or the - // block itself will trigger a pass2 valign at this level. - NS_NOTREACHED("can't get here"); - aCombinedArea = mRect; - return NS_OK; - } - - // topEdge is the y coordinate of the line's top, relative to this - // frame (== in this frames local coordinate system). - nscoord topEdge = -aDistanceFromTopEdge; - - nsRect bbox, childCombinedArea; - nscoord x0 = 0; - nscoord y0 = 0; - nscoord x1 = mRect.width; - nscoord y1 = mRect.height; - nsIFrame* frame = mFrames.FirstChild(); - while (nsnull != frame) { - const nsStyleText* textStyle; - frame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)textStyle); - nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit(); - frame->GetRect(bbox); - - if (eStyleUnit_Enumerated == verticalAlignUnit) { - PRUint8 verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue(); - if (NS_STYLE_VERTICAL_ALIGN_TOP == verticalAlignEnum) { - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(frame, &aParentReflowState, - margin); - nsCSSFrameType frameType = - nsHTMLReflowState::DetermineFrameType(frame); - bbox.y = topEdge + margin.top; - if (NS_CSS_FRAME_TYPE_INLINE == frameType) { - nsMargin bp; - nsHTMLReflowState::ComputeBorderPaddingFor(frame, - &aParentReflowState, bp); - bbox.y -= bp.top; - } - frame->SetRect(bbox); - } - else if (NS_STYLE_VERTICAL_ALIGN_BOTTOM == verticalAlignEnum) { - nsMargin margin; - nsHTMLReflowState::ComputeMarginFor(frame, &aParentReflowState, - margin); - nsCSSFrameType frameType = - nsHTMLReflowState::DetermineFrameType(frame); - bbox.y = topEdge + aLineHeight - bbox.height - margin.bottom; - if (NS_CSS_FRAME_TYPE_INLINE == frameType) { - nsMargin bp; - nsHTMLReflowState::ComputeBorderPaddingFor(frame, - &aParentReflowState, bp); - bbox.y += bp.bottom; - } - frame->SetRect(bbox); - } - } - - // Perform pass2 vertical alignment for top/bottom aligned - // frames that are not our direct descendants. - nsIHTMLReflow* ihr; - nsresult rv = frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr); - if (NS_SUCCEEDED(rv)) { - nsSize availSize(0, 0); - // XXX whacky: we should be passing in the childs reflow state, right? - nsHTMLReflowState ourReflowState(aPresContext, aParentReflowState, - this, availSize); - nscoord distanceFromTopEdge = bbox.y - topEdge; - ihr->VerticalAlignFrames(aPresContext, ourReflowState, aLineHeight, - distanceFromTopEdge, childCombinedArea); - nscoord x = childCombinedArea.x; - if (x < x0) x0 = x; - nscoord y = childCombinedArea.y; - if (y < y0) y0 = y; - nscoord xmost = childCombinedArea.XMost(); - if (xmost > x1) x1 = xmost; - nscoord ymost = childCombinedArea.YMost(); - if (ymost > y1) y1 = ymost; - } - - frame->GetNextSibling(&frame); - } - - aCombinedArea.x = mRect.x + x0; - aCombinedArea.y = mRect.y + y0; - aCombinedArea.width = x1 - x0; - aCombinedArea.height = y1 - y0; - - // Update our outside-children flag bit - if ((x0 < 0) || (y0 < 0) || (x1 > mRect.width) || (y1 > mRect.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - return NS_OK; -} - void nsInlineFrame::DrainOverflow() { @@ -1427,35 +1312,19 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext& aPresContext, nsresult rv = NS_OK; aStatus = NS_FRAME_COMPLETE; - nsInlineReflow ir(*aReflowState.lineLayout, aReflowState, this, PR_FALSE, - nsnull != aMetrics.maxElementSize); - irs.mInlineReflow = &ir; - ir.SetNextRCFrame(irs.mNextRCFrame); - aReflowState.lineLayout->PushInline(&ir); - - // Compute available area - nscoord x = aReflowState.mComputedBorderPadding.left; + nsLineLayout* lineLayout = aReflowState.lineLayout; + nscoord leftEdge = 0; + if (nsnull == mPrevInFlow) { + leftEdge = aReflowState.mComputedBorderPadding.left; + } nscoord availableWidth = aReflowState.availableWidth; if (NS_UNCONSTRAINEDSIZE != availableWidth) { - if (nsnull != mPrevInFlow) { - x = 0; - availableWidth -= aReflowState.mComputedBorderPadding.right + - aReflowState.computedMargin.right; - } - else { - availableWidth -= aReflowState.mComputedBorderPadding.left + - aReflowState.computedMargin.left + - aReflowState.mComputedBorderPadding.right + - aReflowState.computedMargin.right; - } + // Subtract off left and right border+padding from availableWidth + availableWidth -= leftEdge; + availableWidth -= aReflowState.mComputedBorderPadding.right; } - nscoord y = aReflowState.mComputedBorderPadding.top; - nscoord availableHeight = aReflowState.availableHeight; - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) { - availableHeight -= aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.right; - } - ir.Init(x, y, availableWidth, availableHeight); + lineLayout->BeginSpan(this, &aReflowState, + leftEdge, leftEdge + availableWidth); // First reflow our current children nsIFrame* frame = mFrames.FirstChild(); @@ -1489,37 +1358,99 @@ nsInlineFrame::ReflowInlineFrames(nsIPresContext& aPresContext, irs.mPrevFrame = frame; } } - - // Compute final metrics - if (NS_SUCCEEDED(rv)) { -#ifdef NS_DEBUG - if (NS_FRAME_COMPLETE == aStatus) { - // We can't be complete AND have overflow frames! - NS_ASSERTION(mOverflowFrames.IsEmpty(), "whoops"); - } +#ifdef DEBUG + if (NS_FRAME_COMPLETE == aStatus) { + // We can't be complete AND have overflow frames! + NS_ASSERTION(mOverflowFrames.IsEmpty(), "whoops"); + } #endif - nsInlineReflow* ir = irs.mInlineReflow; - nsRect bbox; - ir->VerticalAlignFrames(bbox, aMetrics.ascent, aMetrics.descent); - ir->RelativePositionFrames(aMetrics.mCombinedArea); - aMetrics.width = bbox.XMost(); + + // If after reflowing our children they take up no area then make + // sure that we don't either. + nsSize size; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + if ((0 == size.height) && (0 == size.width)) { + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = 0; + aMetrics.maxElementSize->height = 0; + } + } + else { + // Compute final width + aMetrics.width = size.width; + if (nsnull == mPrevInFlow) { + aMetrics.width += aReflowState.mComputedBorderPadding.left; + } if (NS_FRAME_IS_COMPLETE(aStatus)) { aMetrics.width += aReflowState.mComputedBorderPadding.right; } - aMetrics.height = bbox.height + aReflowState.mComputedBorderPadding.top + + + // Compute final height. The height of our box is the sum of our + // font size plus the top and bottom border and padding. The height + // of children do not affect our height. + // + // Note 2: we use the actual font height for sizing our selves instead + // of the computed font height. On systems where they disagree the + // actual font height is more appropriate. + const nsStyleFont* font; + GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); + aReflowState.rendContext->SetFont(font->mFont); + nsIFontMetrics* fm; + aReflowState.rendContext->GetFontMetrics(fm); + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom; -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": metrics=%d,%d ascent=%d descent=%d\n", - aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); -#endif - aMetrics.mCarriedOutTopMargin = 0; - aMetrics.mCarriedOutBottomMargin = 0; - if (nsnull != aMetrics.maxElementSize) { - *aMetrics.maxElementSize = ir->GetMaxElementSize(); + +#if defined(DEBUG) && defined(XP_UNIX) + static PRBool useComputedHeight = PR_FALSE; + static PRBool firstTime = 1; + if (firstTime) { + if (getenv("GECKO_USE_COMPUTED_HEIGHT")) { + useComputedHeight = PR_TRUE; + } } + if (useComputedHeight) { + // Special debug code that violates the above CSS2 spec + // clarification. Why? So that we can predictably compute the values + // for testing layout. + nscoord computedHeight = aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom + + font->mFont.size; + if (computedHeight != aMetrics.height) { + if (0 == (mState & 0x80000000)) { + nsFrame::ListTag(stdout, this); + printf(": using computedHeight %d instead of actual height %d\n", + computedHeight, aMetrics.height); + mState |= 0x80000000; + } + aMetrics.height = computedHeight; + } + } +#endif + + NS_RELEASE(fm); } - aReflowState.lineLayout->PopInline(); + + // For now our combined area is zero. The real value will be + // computed during vertical alignment of the line we are on. + aMetrics.mCombinedArea.x = 0; + aMetrics.mCombinedArea.y = 0; + aMetrics.mCombinedArea.width = aMetrics.width; + aMetrics.mCombinedArea.height = aMetrics.height; + +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": metrics=%d,%d ascent=%d descent=%d\n", + aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); +#endif return rv; } @@ -1543,8 +1474,8 @@ nsInlineFrame::ReflowInlineFrame(nsIPresContext& aPresContext, return NS_OK; } - nsInlineReflow* ir = irs.mInlineReflow; - nsresult rv = ir->ReflowFrame(aFrame, PR_FALSE/* XXX */, aStatus); + nsLineLayout* lineLayout = aReflowState.lineLayout; + nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); if (NS_FAILED(rv)) { return rv; } @@ -1656,7 +1587,7 @@ nsInlineFrame::PushFrames(nsIFrame* aFromChild, nsIFrame* aPrevSibling) { NS_PRECONDITION(nsnull != aFromChild, "null pointer"); NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); -#ifdef NS_DEBUG +#ifdef DEBUG nsIFrame* prevNextSibling; aPrevSibling->GetNextSibling(&prevNextSibling); NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); diff --git a/mozilla/layout/html/base/src/nsInlineReflow.cpp b/mozilla/layout/html/base/src/nsInlineReflow.cpp index e44087d8f0f..d07e8a5074a 100644 --- a/mozilla/layout/html/base/src/nsInlineReflow.cpp +++ b/mozilla/layout/html/base/src/nsInlineReflow.cpp @@ -1,3 +1,4 @@ +#if 0 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License @@ -657,6 +658,14 @@ nsInlineReflow::VerticalAlignFrames(nsRect& aLineBox, nscoord& aMaxAscent, nscoord& aMaxDescent) { +#if 1 + aLineBox.x = mLeftEdge; + aLineBox.y = mTopEdge; + aLineBox.width = mX - mLeftEdge; + aLineBox.height = mMinLineHeight; + aMaxAscent = 0; + aMaxDescent = 0; +#else PerFrameData* pfd0 = mFrameDataBase; PerFrameData* end = pfd0 + mFrameNum; @@ -1011,6 +1020,7 @@ nsInlineReflow::VerticalAlignFrames(nsRect& aLineBox, aLineBox.x, aLineBox.y, aLineBox.width, aLineBox.height, aMaxAscent, aMaxDescent); #endif +#endif } void @@ -1230,3 +1240,4 @@ nsInlineReflow::JustifyFrames(nscoord aMaxWidth, nsRect& aLineBox) } } } +#endif diff --git a/mozilla/layout/html/base/src/nsInlineReflow.h b/mozilla/layout/html/base/src/nsInlineReflow.h index a64bb35aabf..b8b85134f92 100644 --- a/mozilla/layout/html/base/src/nsInlineReflow.h +++ b/mozilla/layout/html/base/src/nsInlineReflow.h @@ -1,3 +1,4 @@ +#if 0 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License @@ -109,6 +110,10 @@ public: return mRightEdge - mX; } + nscoord GetWidth() const { + return mX - mLeftEdge; + } + PRBool IsZeroHeight() const; protected: @@ -193,3 +198,4 @@ protected: }; #endif /* nsInlineReflow_h___ */ +#endif diff --git a/mozilla/layout/html/base/src/nsLineBox.cpp b/mozilla/layout/html/base/src/nsLineBox.cpp index 251458a8c4d..004c3820b71 100644 --- a/mozilla/layout/html/base/src/nsLineBox.cpp +++ b/mozilla/layout/html/base/src/nsLineBox.cpp @@ -46,16 +46,19 @@ nsLineBox::~nsLineBox() static void ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters) { + nsAutoString frameName; PRInt32 j, i, n = aFloaters->Count(); for (i = 0; i < n; i++) { for (j = aIndent; --j >= 0; ) fputs(" ", out); nsPlaceholderFrame* ph = (nsPlaceholderFrame*) aFloaters->ElementAt(i); if (nsnull != ph) { - fprintf(out, "placeholder@%p\n", ph); + fprintf(out, "placeholder@%p ", ph); nsIFrame* frame = ph->GetAnchoredItem(); if (nsnull != frame) { - frame->List(out, aIndent + 1); + frame->GetFrameName(frameName); + fputs(frameName, out); } + fprintf(out, "\n"); } } } @@ -277,14 +280,7 @@ nsLineBox::UnplaceFloaters(nsISpaceManager* aSpaceManager) PRBool nsLineBox::CheckIsBlock() const { - nsIFrame* frame = mFirstChild; - const nsStyleDisplay* display; - frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) display); - const nsStylePosition* position; - frame->GetStyleData(eStyleStruct_Position, - (const nsStyleStruct*&) position); - PRBool isBlock = nsLineLayout::TreatFrameAsBlock(display, position); + PRBool isBlock = nsLineLayout::TreatFrameAsBlock(mFirstChild); return isBlock == IsBlock(); } #endif diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index 9a7cb8d366f..274f605c6b8 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -16,12 +16,38 @@ * Corporation. Portions created by Netscape are Copyright (C) 1998 * Netscape Communications Corporation. All Rights Reserved. */ +#include "nsCOMPtr.h" #include "nsLineLayout.h" -#include "nsInlineReflow.h" #include "nsStyleConsts.h" +#include "nsHTMLContainerFrame.h" +#include "nsHTMLIIDs.h" +#include "nsISpaceManager.h" #include "nsIStyleContext.h" #include "nsIPresContext.h" #include "nsIFontMetrics.h" +#include "nsIRenderingContext.h" + +#ifdef DEBUG +#undef NOISY_HORIZONTAL_ALIGN +#undef REALLY_NOISY_HORIZONTAL_ALIGN +#undef NOISY_VERTICAL_ALIGN +#undef REALLY_NOISY_VERTICAL_ALIGN +#undef NOISY_REFLOW +#undef REALLY_NOISY_REFLOW +#undef NOISY_PUSHING +#undef REALLY_NOISY_PUSHING +#define DEBUG_ADD_TEXT +#else +#undef NOISY_HORIZONTAL_ALIGN +#undef REALLY_NOISY_HORIZONTAL_ALIGN +#undef NOISY_VERTICAL_ALIGN +#undef REALLY_NOISY_VERTICAL_ALIGN +#undef NOISY_REFLOW +#undef REALLY_NOISY_REFLOW +#undef NOISY_PUSHING +#undef REALLY_NOISY_PUSHING +#undef DEBUG_ADD_TEXT +#endif nsTextRun::nsTextRun() { @@ -44,96 +70,1716 @@ nsTextRun::List(FILE* out, PRInt32 aIndent) nsAutoString tmp; text->GetFrameName(tmp); fputs(tmp, out); - printf(" "); + printf("@%p ", text); } fputs(">\n", out); } //---------------------------------------------------------------------- +#define PLACED_LEFT 0x1 +#define PLACED_RIGHT 0x2 + +#define NUM_SPAN_DATA (sizeof(mSpanDataBuf) / sizeof(mSpanDataBuf[0])) +#define NUM_FRAME_DATA (sizeof(mFrameDataBuf) / sizeof(mFrameDataBuf[0])) + nsLineLayout::nsLineLayout(nsIPresContext& aPresContext, - nsISpaceManager* aSpaceManager) - : mPresContext(aPresContext) + nsISpaceManager* aSpaceManager, + const nsHTMLReflowState* aOuterReflowState, + PRBool aComputeMaxElementSize) + : mPresContext(aPresContext), + mSpaceManager(aSpaceManager), + mBlockReflowState(aOuterReflowState), + mComputeMaxElementSize(aComputeMaxElementSize) { - mSpaceManager = aSpaceManager; - mListPositionOutside = PR_FALSE; + // Stash away some style data that we need + aOuterReflowState->frame->GetStyleData(eStyleStruct_Text, + (const nsStyleStruct*&) mStyleText); + mTextAlign = mStyleText->mTextAlign; + switch (mStyleText->mWhiteSpace) { + case NS_STYLE_WHITESPACE_PRE: + case NS_STYLE_WHITESPACE_NOWRAP: + mNoWrap = PR_TRUE; + break; + default: + mNoWrap = PR_FALSE; + break; + } + mDirection = aOuterReflowState->mStyleDisplay->mDirection; + mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext, + aOuterReflowState->frame); + mBRFrame = nsnull; mLineNumber = 0; mColumn = 0; - mUnderstandsWhiteSpace = PR_FALSE; mEndsInWhiteSpace = PR_TRUE; + mUnderstandsWhiteSpace = PR_FALSE; + mFirstLetterStyleOK = PR_FALSE; + mIsTopOfPage = PR_FALSE; + mWasInWord = PR_FALSE; + mCanBreakBeforeFrame = PR_FALSE; + mUpdatedBand = PR_FALSE; + mPlacedFloaters = 0; + mTotalPlacedFrames = 0; + mTopEdge = mBottomEdge = 0; + mReflowTextRuns = nsnull; + mTextRun = nsnull; - mTextRuns = nsnull; - ResetTextRuns(); -} + // XXX Do this on demand to avoid extra setup time + // Place the baked-in per-frame-data on the frame free list + PerFrameData** pfdp = &mFrameFreeList; + PerFrameData* pfd = mFrameDataBuf; + PerFrameData* endpfd = pfd + NUM_FRAME_DATA; + while (pfd < endpfd) { +#ifdef DEBUG + nsCRT::memset(pfd, 0xEE, sizeof(*pfd)); +#endif + *pfdp = pfd; + pfdp = &pfd->mNext; + pfd++; + } + *pfdp = nsnull; -nsLineLayout::~nsLineLayout() -{ - nsTextRun::DeleteTextRuns(mTextRuns); -} + // XXX Do this on demand to avoid extra setup time + // Place the baked-in per-span-data on the span free list + PerSpanData** psdp = &mSpanFreeList; + PerSpanData* psd = mSpanDataBuf; + PerSpanData* endpsd = psd + NUM_SPAN_DATA; + while (psd < endpsd) { +#ifdef DEBUG + nsCRT::memset(psd, 0xEE, sizeof(*psd)); +#endif + *psdp = psd; + psdp = &psd->mNext; + psd++; + } + *psdp = nsnull; + + mCurrentSpan = mRootSpan = mLastSpan = nsnull; + mSpanDepth = 0; -void -nsLineLayout::ResetTextRuns() -{ - nsTextRun::DeleteTextRuns(mTextRuns); mTextRuns = nsnull; mTextRunP = &mTextRuns; mNewTextRun = nsnull; } -nsTextRun* -nsLineLayout::TakeTextRuns() +nsLineLayout::nsLineLayout(nsIPresContext& aPresContext) + : mPresContext(aPresContext) { - nsTextRun* result = mTextRuns; mTextRuns = nsnull; - ResetTextRuns(); - return result; + mTextRunP = &mTextRuns; + mNewTextRun = nsnull; + mRootSpan = nsnull; + mSpanFreeList = nsnull; + mFrameFreeList = nsnull; +} + +nsLineLayout::~nsLineLayout() +{ + NS_ASSERTION(nsnull == mRootSpan, "bad line-layout user"); + nsTextRun::DeleteTextRuns(mTextRuns); + + // Free up all of the per-span-data items that were allocated on the heap + PerSpanData* psd = mSpanFreeList; + while (nsnull != psd) { + PerSpanData* nextSpan = psd->mNext; + if ((psd < &mSpanDataBuf[0]) || (psd >= &mSpanDataBuf[NUM_SPAN_DATA])) { + delete psd; + } + psd = nextSpan; + } + + // Free up all of the per-frame-data items that were allocated on the heap + PerFrameData* pfd = mFrameFreeList; + while (nsnull != pfd) { + PerFrameData* nextFrame = pfd->mNext; + if ((pfd < &mFrameDataBuf[0]) || (pfd >= &mFrameDataBuf[NUM_FRAME_DATA])) { + delete pfd; + } + pfd = nextFrame; + } } void -nsLineLayout::EndTextRun() +nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aIsTopOfPage) { - mNewTextRun = nsnull; + NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user"); +#ifdef DEBUG + if ((aWidth > 200000) && (aWidth != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": Init: bad caller: width WAS %d(0x%x)\n", + aWidth, aWidth); + aWidth = NS_UNCONSTRAINEDSIZE; + } + if ((aHeight > 200000) && (aHeight != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": Init: bad caller: height WAS %d(0x%x)\n", + aHeight, aHeight); + aHeight = NS_UNCONSTRAINEDSIZE; + } +#endif +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": BeginLineReflow: %d,%d,%d,%d %s\n", + aX, aY, aWidth, aHeight, + aIsTopOfPage ? "top-of-page" : ""); +#endif + + mBRFrame = nsnull; + mColumn = 0; + mEndsInWhiteSpace = PR_TRUE; + mUnderstandsWhiteSpace = PR_FALSE; + mFirstLetterStyleOK = PR_FALSE; + mIsTopOfPage = aIsTopOfPage; + mCanBreakBeforeFrame = PR_FALSE; + mUpdatedBand = PR_FALSE; + mPlacedFloaters = 0; + mTotalPlacedFrames = 0; + mSpanDepth = 0; + mMaxTopBoxHeight = mMaxBottomBoxHeight = 0; + + ForgetWordFrames(); + + PerSpanData* psd; + NewPerSpanData(&psd); + mCurrentSpan = mRootSpan = psd; + psd->mReflowState = mBlockReflowState; + psd->mLeftEdge = aX; + psd->mX = aX; + if (NS_UNCONSTRAINEDSIZE == aWidth) { + psd->mRightEdge = NS_UNCONSTRAINEDSIZE; + } + else { + psd->mRightEdge = aX + aWidth; + } + + mTopEdge = aY; + if (NS_UNCONSTRAINEDSIZE == aHeight) { + mBottomEdge = NS_UNCONSTRAINEDSIZE; + } + else { + mBottomEdge = aY + aHeight; + } +} + +void +nsLineLayout::EndLineReflow() +{ +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": EndLineReflow: width=%d\n", mRootSpan->mX - mRootSpan->mLeftEdge); +#endif + + PerSpanData* psd = mRootSpan; + while (nsnull != psd) { + // Put frames on free list + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + PerFrameData* nextFrame = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + pfd = nextFrame; + } + + // Put span on free list + PerSpanData* nextSpan = psd->mNext; + psd->mNext = mSpanFreeList; + mSpanFreeList = psd; + psd = nextSpan; + } + mCurrentSpan = mRootSpan = mLastSpan = nsnull; +} + +void +nsLineLayout::UpdateBand(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aPlacedLeftFloater) +{ + PerSpanData* psd = mRootSpan; + NS_PRECONDITION(psd->mX == psd->mLeftEdge, "update-band called late"); +#ifdef DEBUG + if ((aWidth > 200000) && (aWidth != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: bad caller: width WAS %d(0x%x)\n", + aWidth, aWidth); + aWidth = NS_UNCONSTRAINEDSIZE; + } + if ((aHeight > 200000) && (aHeight != NS_UNCONSTRAINEDSIZE)) { + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: bad caller: height WAS %d(0x%x)\n", + aHeight, aHeight); + aHeight = NS_UNCONSTRAINEDSIZE; + } +#endif +#ifdef NOISY_REFLOW + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": UpdateBand: %d,%d,%d,%d %s\n", + aX, aY, aWidth, aHeight, + aPlacedLeftFloater ? "placed-left-floater" : ""); +#endif + + psd->mLeftEdge = aX; + psd->mX = aX; + if (NS_UNCONSTRAINEDSIZE == aWidth) { + psd->mRightEdge = NS_UNCONSTRAINEDSIZE; + } + else { + psd->mRightEdge = aX + aWidth; + } + mTopEdge = aY; + if (NS_UNCONSTRAINEDSIZE == aHeight) { + mBottomEdge = NS_UNCONSTRAINEDSIZE; + } + else { + mBottomEdge = aY + aHeight; + } + mUpdatedBand = PR_TRUE; + mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT); +} + +void +nsLineLayout::UpdateFrames() +{ + if (NS_STYLE_DIRECTION_LTR == mDirection) { + if (PLACED_LEFT & mPlacedFloaters) { + // Note: Only adjust the outermost frames (the ones that are + // direct children of the block), not the ones in the child + // spans. The reason is simple: the frames in the spans have + // coordinates local to their parent therefore they are moved + // when their parent span is moved. + PerSpanData* psd = mRootSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + pfd->mBounds.x = psd->mX; + pfd = pfd->mNext; + } + } + } + else if (PLACED_RIGHT & mPlacedFloaters) { + // XXX handle DIR=right-to-left + } } nsresult -nsLineLayout::AddText(nsIFrame* aTextFrame) +nsLineLayout::NewPerSpanData(PerSpanData** aResult) { - if (nsnull == mNewTextRun) { - mNewTextRun = new nsTextRun(); - if (nsnull == mNewTextRun) { + PerSpanData* psd = mSpanFreeList; + if (nsnull == psd) { + psd = new PerSpanData; + if (nsnull == psd) { return NS_ERROR_OUT_OF_MEMORY; } - *mTextRunP = mNewTextRun; - mTextRunP = &mNewTextRun->mNext; } - mNewTextRun->mArray.AppendElement(aTextFrame); - return NS_OK;/* XXX */ + else { + mSpanFreeList = psd->mNext; + } + psd->mParent = nsnull; + psd->mFrame = nsnull; + psd->mFirstFrame = nsnull; + psd->mLastFrame = nsnull; + psd->mNext = nsnull; + + // Link new span to the end of the span list + if (nsnull == mLastSpan) { + psd->mPrev = nsnull; + } + else { + mLastSpan->mNext = psd; + psd->mPrev = mLastSpan; + } + mLastSpan = psd; + + *aResult = psd; + return NS_OK; } -nsTextRun* -nsLineLayout::FindTextRunFor(nsIFrame* aFrame) +nsresult +nsLineLayout::BeginSpan(nsIFrame* aFrame, + const nsHTMLReflowState* aSpanReflowState, + nscoord aLeftEdge, + nscoord aRightEdge) { - // Only the first-in-flows are present in the text run list so - // backup from the argument frame to its first-in-flow. - for (;;) { - nsIFrame* prevInFlow; - aFrame->GetPrevInFlow(&prevInFlow); - if (nsnull == prevInFlow) { - break; +#ifdef NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth+1); + nsFrame::ListTag(stdout, aFrame); + printf(": BeginSpan leftEdge=%d rightEdge=%d\n", aLeftEdge, aRightEdge); +#endif + + PerSpanData* psd; + nsresult rv = NewPerSpanData(&psd); + if (NS_SUCCEEDED(rv)) { + // Link up span frame's pfd to point to its child span data + PerFrameData* pfd = mCurrentSpan->mLastFrame; + NS_ASSERTION(pfd->mFrame == aFrame, "huh?"); + pfd->mSpan = psd; + + // Init new span + psd->mFrame = pfd; + psd->mParent = mCurrentSpan; + psd->mReflowState = aSpanReflowState; + psd->mLeftEdge = aLeftEdge; + psd->mX = aLeftEdge; + psd->mRightEdge = aRightEdge; + + // Switch to new span + mCurrentSpan = psd; + mSpanDepth++; + } + return rv; +} + +void +nsLineLayout::EndSpan(nsIFrame* aFrame, + nsSize& aSizeResult, + nsSize* aMaxElementSize) +{ + NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span"); +#ifdef NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + nsFrame::ListTag(stdout, aFrame); + printf(": EndSpan width=%d\n", mCurrentSpan->mX - mCurrentSpan->mLeftEdge); +#endif + PerSpanData* psd = mCurrentSpan; + nscoord width = 0; + nscoord maxHeight = 0; + nscoord maxElementWidth = 0; + nscoord maxElementHeight = 0; + if (nsnull != psd->mLastFrame) { + width = psd->mX - psd->mLeftEdge; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height; + + // Compute max-element-size if necessary + if (aMaxElementSize) { + nscoord mw = pfd->mMaxElementSize.width + + pfd->mMargin.left + pfd->mMargin.right; + if (maxElementWidth < mw) { + maxElementWidth = mw; + } + nscoord mh = pfd->mMaxElementSize.height + + pfd->mMargin.top + pfd->mMargin.bottom; + if (maxElementHeight < mh) { + maxElementHeight = mh; + } + } + pfd = pfd->mNext; } - aFrame = prevInFlow; + } + aSizeResult.width = width; + aSizeResult.height = maxHeight; + if (aMaxElementSize) { + aMaxElementSize->width = maxElementWidth; + aMaxElementSize->height = maxElementHeight; } - // Now look for the frame in each run - nsTextRun* run = mReflowTextRuns; - while (nsnull != run) { - PRInt32 ix = run->mArray.IndexOf(aFrame); - if (ix >= 0) { - return run; - } - run = run->mNext; + mSpanDepth--; + mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out! + mCurrentSpan = mCurrentSpan->mParent; +} + +PRInt32 +nsLineLayout::GetCurrentSpanCount() const +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + PRInt32 count = 0; + PerFrameData* pfd = mRootSpan->mFirstFrame; + while (nsnull != pfd) { + count++; + pfd = pfd->mNext; + } + return count; +} + +void +nsLineLayout::SplitLineTo(PRInt32 aNewCount) +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + +#ifdef REALLY_NOISY_PUSHING + printf("SplitLineTo %d (current count=%d); before:\n", aNewCount, + GetCurrentSpanCount()); + DumpPerSpanData(mRootSpan, 1); +#endif + PerSpanData* psd = mRootSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (--aNewCount == 0) { + // Truncate list at pfd (we keep pfd, but anything following is freed) + PerFrameData* next = pfd->mNext; + pfd->mNext = nsnull; + psd->mLastFrame = pfd; + + // Now release all of the frames following pfd + pfd = next; + while (nsnull != pfd) { + next = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } + pfd = next; + } + break; + } + pfd = pfd->mNext; + } +#ifdef NOISY_PUSHING + printf("SplitLineTo %d (current count=%d); after:\n", aNewCount, + GetCurrentSpanCount()); + DumpPerSpanData(mRootSpan, 1); +#endif +} + +void +nsLineLayout::PushFrame(nsIFrame* aFrame) +{ + PerSpanData* psd = mCurrentSpan; + NS_ASSERTION(psd->mLastFrame->mFrame == aFrame, "pushing non-last frame"); + +#ifdef REALLY_NOISY_PUSHING + nsFrame::IndentBy(stdout, mSpanDepth); + printf("PushFrame %p, before:\n", psd); + DumpPerSpanData(psd, 1); +#endif + + // Take the last frame off of the span's frame list + PerFrameData* pfd = psd->mLastFrame; + if (pfd == psd->mFirstFrame) { + // We are pushing away the only frame...empty the list + psd->mFirstFrame = nsnull; + psd->mLastFrame = nsnull; + } + else { + PerFrameData* prevFrame = pfd->mPrev; + prevFrame->mNext = nsnull; + psd->mLastFrame = prevFrame; + } + + // Now free it, and if it has a span, free that too + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } +#ifdef NOISY_PUSHING + nsFrame::IndentBy(stdout, mSpanDepth); + printf("PushFrame: %p after:\n", psd); + DumpPerSpanData(psd, 1); +#endif +} + +void +nsLineLayout::FreeSpan(PerSpanData* psd) +{ + // Take span out of the list + if (nsnull != psd->mNext) psd->mNext->mPrev = psd->mPrev; + if (nsnull != psd->mPrev) psd->mPrev->mNext = psd->mNext; + + // Free its frames + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (nsnull != pfd->mSpan) { + FreeSpan(pfd->mSpan); + } + PerFrameData* next = pfd->mNext; + pfd->mNext = mFrameFreeList; + mFrameFreeList = pfd; + pfd = next; + } +} + +PRBool +nsLineLayout::IsZeroHeight() +{ + PerSpanData* psd = mCurrentSpan; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + if (0 != pfd->mBounds.height) { + return PR_FALSE; + } + pfd = pfd->mNext; + } + return PR_TRUE; +} + +nsresult +nsLineLayout::NewPerFrameData(PerFrameData** aResult) +{ + PerFrameData* pfd = mFrameFreeList; + if (nsnull == pfd) { + pfd = new PerFrameData; + if (nsnull == pfd) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + else { + mFrameFreeList = pfd->mNext; + } + pfd->mSpan = nsnull; + pfd->mNext = nsnull; + *aResult = pfd; + return NS_OK; +} + +nsresult +nsLineLayout::ReflowFrame(nsIFrame* aFrame, + nsIFrame** aNextRCFrame, + nsReflowStatus& aReflowStatus) +{ + PerFrameData* pfd; + nsresult rv = NewPerFrameData(&pfd); + if (NS_FAILED(rv)) { + return rv; + } + PerSpanData* psd = mCurrentSpan; + psd->AppendFrame(pfd); + +#ifdef REALLY_NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + printf("%p: Begin ReflowFrame pfd=%p ", psd, pfd); + nsFrame::ListTag(stdout, aFrame); + printf("\n"); +#endif + + // Compute the available size for the frame. This available width + // includes room for the side margins and for the text-indent. + nsSize availSize; + if (NS_UNCONSTRAINEDSIZE == psd->mRightEdge) { + availSize.width = NS_UNCONSTRAINEDSIZE; + } + else { + availSize.width = psd->mRightEdge - psd->mX; + if (mNoWrap) { + // XXX Shouldn't this use NS_UNCONSTRAINEDSIZE? + availSize.width = psd->mReflowState->availableWidth; + } + } + if (NS_UNCONSTRAINEDSIZE == mBottomEdge) { + availSize.height = NS_UNCONSTRAINEDSIZE; + } + else { + availSize.height = mBottomEdge - mTopEdge; + } + + // Get reflow reason set correctly. It's possible that a child was + // created and then it was decided that it could not be reflowed + // (for example, a block frame that isn't at the start of a + // line). In this case the reason will be wrong so we need to check + // the frame state. + nsReflowReason reason = eReflowReason_Resize; + nsFrameState state; + aFrame->GetFrameState(&state); + if (NS_FRAME_FIRST_REFLOW & state) { + reason = eReflowReason_Initial; + } + else if (*aNextRCFrame == aFrame) { + reason = eReflowReason_Incremental; + // Make sure we only incrementally reflow once + *aNextRCFrame = nsnull; + } + + // Setup reflow state for reflowing the frame + nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState, aFrame, + availSize, reason); + reflowState.lineLayout = this; + reflowState.isTopOfPage = mIsTopOfPage; + mUnderstandsWhiteSpace = PR_FALSE; + mCanBreakBeforeFrame = mTotalPlacedFrames > 0; + + // Stash copies of some of the computed state away for later + // (vertical alignment, for example) + pfd->mFrame = aFrame; + pfd->mMargin = reflowState.computedMargin; + pfd->mBorderPadding = reflowState.mComputedBorderPadding; + pfd->mFrameType = reflowState.frameType; + pfd->mRelativePos = + reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE; + if (pfd->mRelativePos) { + pfd->mOffsets = reflowState.computedOffsets; + } + + // Capture this state *before* we reflow the frame in case it clears + // the state out. We need to know how to treat the current frame + // when breaking. + mWasInWord = InWord(); + + // Apply left margins (as appropriate) to the frame computing the + // new starting x,y coordinates for the frame. + ApplyLeftMargin(pfd, reflowState); + + // Let frame know that are reflowing it + nscoord x = pfd->mBounds.x; + nscoord y = pfd->mBounds.y; + nsIHTMLReflow* htmlReflow; + + aFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + htmlReflow->WillReflow(mPresContext); + + // Adjust spacemanager coordinate system for the frame. The + // spacemanager coordinates are inside the current spans + // border+padding, but the x/y coordinates are not (recall that + // frame coordinates are relative to the parents origin and that the + // parents border/padding is inside the parent + // frame. Therefore we have to subtract out the parents + // border+padding before translating. + nsSize innerMaxElementSize; + nsHTMLReflowMetrics metrics(mComputeMaxElementSize + ? &innerMaxElementSize + : nsnull); +#ifdef DEBUG + if (mComputeMaxElementSize) { + metrics.maxElementSize->width = nscoord(0xdeadbeef); + metrics.maxElementSize->height = nscoord(0xdeadbeef); + } +#endif + nscoord tx = x - psd->mReflowState->mComputedBorderPadding.left; + nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top; + mSpaceManager->Translate(tx, ty); + htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus); + mSpaceManager->Translate(-tx, -ty); + +#ifdef DEBUG_kipp + NS_ASSERTION((metrics.width > -200000) && (metrics.width < 200000), "oy"); + NS_ASSERTION((metrics.height > -200000) && (metrics.height < 200000), "oy"); +#endif +#ifdef DEBUG + if (mComputeMaxElementSize && + ((nscoord(0xdeadbeef) == metrics.maxElementSize->width) || + (nscoord(0xdeadbeef) == metrics.maxElementSize->height))) { + printf("nsLineLayout: "); + nsFrame::ListTag(stdout, aFrame); + printf(" didn't set max-element-size!\n"); + metrics.maxElementSize->width = 0; + metrics.maxElementSize->height = 0; + } +#endif + + aFrame->GetFrameState(&state); + if (NS_FRAME_OUTSIDE_CHILDREN & state) { + pfd->mCombinedArea = metrics.mCombinedArea; + } + else { + pfd->mCombinedArea.x = 0; + pfd->mCombinedArea.y = 0; + pfd->mCombinedArea.width = metrics.width; + pfd->mCombinedArea.height = metrics.height; + } + pfd->mBounds.width = metrics.width; + pfd->mBounds.height = metrics.height; + if (mComputeMaxElementSize) { + pfd->mMaxElementSize = *metrics.maxElementSize; + } + + // Now that frame has been reflowed at least one time make sure that + // the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an + // initial reflow reason again. + if (eReflowReason_Initial == reason) { + aFrame->GetFrameState(&state); + aFrame->SetFrameState(state & ~NS_FRAME_FIRST_REFLOW); + } + + if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) { + // If frame is complete and has a next-in-flow, we need to delete + // them now. Do not do this when a break-before is signaled because + // the frame is going to get reflowed again (and may end up wanting + // a next-in-flow where it ends up). + if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { + nsIFrame* kidNextInFlow; + aFrame->GetNextInFlow(&kidNextInFlow); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows. Make sure that we ask + // the right parent to do the removal (it's possible that the + // parent is not this because we are executing pullup code) + nsHTMLContainerFrame* parent; + aFrame->GetParent((nsIFrame**) &parent); + parent->DeleteChildsNextInFlow(mPresContext, aFrame); + } + } + + // See if we can place the frame. If we can't fit it, then we + // return now. + if (CanPlaceFrame(pfd, reflowState, metrics, aReflowStatus)) { + // Place the frame, updating aBounds with the final size and + // location. Then apply the bottom+right margins (as + // appropriate) to the frame. + PlaceFrame(pfd, metrics); + PerSpanData* span = pfd->mSpan; + if (span) { + // The frame we just finished reflowing is an inline + // container. It needs its child frames vertically aligned, + // so do most of it now. + VerticalAlignFrames(span); + } + } + else { + PushFrame(aFrame); + } + } + else { + PushFrame(aFrame); + } + +#ifdef REALLY_NOISY_REFLOW + nsFrame::IndentBy(stdout, mSpanDepth); + printf("End ReflowFrame "); + nsFrame::ListTag(stdout, aFrame); + printf(" status=%x\n", aReflowStatus); +#endif + return rv; +} + +void +nsLineLayout::ApplyLeftMargin(PerFrameData* pfd, + nsHTMLReflowState& aReflowState) +{ + // If this is the first frame in the block, and its the first line + // of a block then see if the text-indent property amounts to + // anything. + nscoord indent = 0; + if (InBlockContext() && (0 == mLineNumber) && + (0 == mTotalPlacedFrames)) { + nsStyleUnit unit = mStyleText->mTextIndent.GetUnit(); + if (eStyleUnit_Coord == unit) { + indent = mStyleText->mTextIndent.GetCoordValue(); + } + else if (eStyleUnit_Percent == unit) { + nscoord width = + nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState->parentReflowState); + if (0 != width) { + indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width); + } + } + } + + // Adjust available width to account for the indent and the margins + aReflowState.availableWidth -= indent + pfd->mMargin.left + + pfd->mMargin.right; + + // NOTE: While the x coordinate remains relative to the parent span, + // the y coordinate is fixed at the top edge for the line. During + // VerticalAlignFrames we will repair this so that the y coordinate + // is properly set and relative to the appropriate span. + PerSpanData* psd = mCurrentSpan; + pfd->mBounds.x = psd->mX + indent; + pfd->mBounds.y = mTopEdge; + + // Compute left margin + nsIFrame* prevInFlow; + switch (aReflowState.mStyleDisplay->mFloats) { + default: + NS_NOTYETIMPLEMENTED("Unsupported floater type"); + // FALL THROUGH + + case NS_STYLE_FLOAT_LEFT: + case NS_STYLE_FLOAT_RIGHT: + // When something is floated, its margins are applied there + // not here. + break; + + case NS_STYLE_FLOAT_NONE: + // Only apply left-margin on the first-in flow for inline frames + pfd->mFrame->GetPrevInFlow(&prevInFlow); + if (nsnull != prevInFlow) { + // Zero this out so that when we compute the max-element-size + // of the frame we will properly avoid adding in the left + // margin. + pfd->mMargin.left = 0; + } + pfd->mBounds.x += pfd->mMargin.left; + break; + } +} + +/** + * See if the frame can be placed now that we know it's desired size. + * We can always place the frame if the line is empty. Note that we + * know that the reflow-status is not a break-before because if it was + * ReflowFrame above would have returned false, preventing this method + * from being called. The logic in this method assumes that. + * + * Note that there is no check against the Y coordinate because we + * assume that the caller will take care of that. + */ +PRBool +nsLineLayout::CanPlaceFrame(PerFrameData* pfd, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) +{ + // Compute right margin to use + nscoord rightMargin = 0; + if (0 != pfd->mBounds.width) { + switch (aReflowState.mStyleDisplay->mFloats) { + default: + NS_NOTYETIMPLEMENTED("Unsupported floater type"); + // FALL THROUGH + + case NS_STYLE_FLOAT_LEFT: + case NS_STYLE_FLOAT_RIGHT: + // When something is floated, its margins are applied there + // not here. + break; + + case NS_STYLE_FLOAT_NONE: + // Only apply right margin for the last-in-flow + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + // Zero this out so that when we compute the + // max-element-size of the frame we will properly avoid + // adding in the right margin. + pfd->mMargin.right = 0; + } + rightMargin = pfd->mMargin.right; + break; + } + } + pfd->mMargin.right = rightMargin; + + // Set outside to PR_TRUE if the result of the reflow leads to the + // frame sticking outside of our available area. + PerSpanData* psd = mCurrentSpan; + PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge; + + // There are several special conditions that exist which allow us to + // ignore outside. If they are true then we can place frame and + // return PR_TRUE. + if (!mCanBreakBeforeFrame || mWasInWord || mNoWrap) { + return PR_TRUE; + } + + if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) { + // Empty frames always fit right where they are + return PR_TRUE; + } + + if (pfd == mCurrentSpan->mFirstFrame) { + return PR_TRUE; + } + + if (outside) { + aStatus = NS_INLINE_LINE_BREAK_BEFORE(); + return PR_FALSE; + } + return PR_TRUE; +} + +/** + * Place the frame. Update running counters. + */ +void +nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics) +{ + // If frame is zero width then do not apply its left and right margins. + PerSpanData* psd = mCurrentSpan; + PRBool emptyFrame = PR_FALSE; + if ((0 == pfd->mBounds.width) && (0 == pfd->mBounds.height)) { + pfd->mBounds.x = psd->mX; + pfd->mBounds.y = mTopEdge; + emptyFrame = PR_TRUE; + } + + // Record ascent and update max-ascent and max-descent values + pfd->mAscent = aMetrics.ascent; + pfd->mDescent = aMetrics.descent; + pfd->mCarriedOutTopMargin = aMetrics.mCarriedOutTopMargin; + pfd->mCarriedOutBottomMargin = aMetrics.mCarriedOutBottomMargin; + + // If the band was updated during the reflow of that frame then we + // need to adjust any prior frames that were reflowed. + if (mUpdatedBand && InBlockContext()) { + UpdateFrames(); + mUpdatedBand = PR_FALSE; + } + + // Advance to next X coordinate + psd->mX = pfd->mBounds.XMost() + pfd->mMargin.right; + + // If the frame is a not aware of white-space and it takes up some + // area, disable leading white-space compression for the next frame + // to be reflowed. + if (!mUnderstandsWhiteSpace && !emptyFrame) { + mEndsInWhiteSpace = PR_FALSE; + } + + // Compute the bottom margin to apply. Note that the margin only + // applies if the frame ends up with a non-zero height. + if (!emptyFrame) { + // Inform line layout that we have placed a non-empty frame + mTotalPlacedFrames++; + } +} + +nsresult +nsLineLayout::AddBulletFrame(nsIFrame* aFrame, + const nsHTMLReflowMetrics& aMetrics) +{ + NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user"); + + PerFrameData* pfd; + nsresult rv = NewPerFrameData(&pfd); + if (NS_SUCCEEDED(rv)) { + mRootSpan->AppendFrame(pfd); + pfd->mFrame = aFrame; + pfd->mMargin.SizeTo(0, 0, 0, 0); + pfd->mBorderPadding.SizeTo(0, 0, 0, 0); + pfd->mFrameType = NS_CSS_FRAME_TYPE_INLINE|NS_FRAME_REPLACED_ELEMENT; + pfd->mRelativePos = PR_FALSE; + pfd->mAscent = aMetrics.ascent; + pfd->mDescent = aMetrics.descent; + aFrame->GetRect(pfd->mBounds); // y value is irrelevant + pfd->mCombinedArea = aMetrics.mCombinedArea; + if (mComputeMaxElementSize) { + pfd->mMaxElementSize.SizeTo(aMetrics.width, aMetrics.height); + } + } + return rv; +} + +#ifdef DEBUG +void +nsLineLayout::DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent) +{ + nsFrame::IndentBy(stdout, aIndent); + printf("%p: left=%d x=%d right=%d prev/next=%p/%p\n", psd, psd->mLeftEdge, + psd->mX, psd->mRightEdge, psd->mPrev, psd->mNext); + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nsFrame::IndentBy(stdout, aIndent+1); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(" %d,%d,%d,%d\n", pfd->mBounds.x, pfd->mBounds.y, + pfd->mBounds.width, pfd->mBounds.height); + if (pfd->mSpan) { + DumpPerSpanData(pfd->mSpan, aIndent + 1); + } + pfd = pfd->mNext; + } +} +#endif + +#define VALIGN_OTHER 0 +#define VALIGN_TOP 1 +#define VALIGN_BOTTOM 2 + +void +nsLineLayout::VerticalAlignFrames(nsRect& aLineBoxResult, + nsSize& aMaxElementSizeResult) +{ + // Synthesize a PerFrameData for the block frame + PerFrameData rootPFD; + rootPFD.mFrame = mBlockReflowState->frame; + rootPFD.mFrameType = mBlockReflowState->frameType; + rootPFD.mAscent = 0; + rootPFD.mDescent = 0; + mRootSpan->mFrame = &rootPFD; + + // Partially place the children of the block frame. The baseline for + // this operation is set to zero so that the y coordinates for all + // of the placed children will be relative to there. + PerSpanData* psd = mRootSpan; + VerticalAlignFrames(psd); + + // Compute the line-height. The line-height will be the larger of: + // + // [1] maxY - minY (the distance between the highest childs top edge + // and the lowest childs bottom edge) + // + // [2] the maximum logical box height (since not every frame may have + // participated in #1; for example: top/bottom aligned frames) + // + // [3] the minimum line height (line-height property set on the + // block frame) + nscoord lineHeight = psd->mMaxY - psd->mMinY; + + // Now that the line-height is computed, we need to know where the + // baseline is in the line. Position baseline so that mMinY is just + // inside the top of the line box. + nscoord baselineY; + if (psd->mMinY < 0) { + baselineY = mTopEdge - psd->mMinY; + } + else { + baselineY = mTopEdge; + } + + // It's possible that the line-height isn't tall enough because of + // the blocks minimum line-height. + if (0 != lineHeight) { + // If line contains nothing but empty boxes that have no height + // then don't apply the min-line-height. + // + // Note: This is how we hide lines that contain nothing but + // compressed whitespace. + if (lineHeight < mMinLineHeight) { + // Apply half of the extra space to the top of the line as top + // leading + nscoord extra = mMinLineHeight - lineHeight; + baselineY += extra / 2; + lineHeight = mMinLineHeight; + } + } + + // It's also possible that the line-height isn't tall enough because + // of top/bottom aligned elements that were not accounted for in + // min/max Y. + // + // The CSS2 spec doesn't really say what happens when to the + // baseline in this situations. What we do is if the largest top + // aligned box height is greater than the line-height then we leave + // the baseline alone. If the largest bottom aligned box is greater + // than the line-height then we slide the baseline down by the extra + // amount. + // + // Navigator 4 gives precedence to the first top/bottom aligned + // object. We just let bottom aligned objects win. + if (lineHeight < mMaxBottomBoxHeight) { + // When the line is shorter than the maximum top aligned box + nscoord extra = mMaxBottomBoxHeight - lineHeight; + baselineY += extra; + lineHeight = mMaxBottomBoxHeight; + } + if (lineHeight < mMaxTopBoxHeight) { + lineHeight = mMaxTopBoxHeight; + } +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> lineHeight=%d baselineY=%d\n", lineHeight, baselineY); +#endif + + // Now position all of the frames in the root span. We will also + // recurse over the child spans and place any top/bottom aligned + // frames we find. + // XXX PERFORMANCE: set a bit per-span to avoid the extra work + // (propogate it upward too) + PerFrameData* pfd = psd->mFirstFrame; + nscoord maxElementWidth = 0; + nscoord maxElementHeight = 0; + while (nsnull != pfd) { + // Compute max-element-size if necessary + if (mComputeMaxElementSize) { + nscoord mw = pfd->mMaxElementSize.width + + pfd->mMargin.left + pfd->mMargin.right; + if (maxElementWidth < mw) { + maxElementWidth = mw; + } + nscoord mh = pfd->mMaxElementSize.height + + pfd->mMargin.top + pfd->mMargin.bottom; + if (maxElementHeight < mh) { + maxElementHeight = mh; + } + } + PerSpanData* span = pfd->mSpan; + switch (pfd->mVerticalAlign) { + case VALIGN_TOP: + if (span) { + pfd->mBounds.y = mTopEdge - pfd->mBorderPadding.top + + span->mTopLeading; + } + else { + pfd->mBounds.y = mTopEdge + pfd->mMargin.top; + } + break; + case VALIGN_BOTTOM: + if (span) { + // Compute bottom leading + pfd->mBounds.y = mTopEdge + lineHeight - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + span->mBottomLeading; + } + else { + pfd->mBounds.y = mTopEdge + lineHeight - pfd->mMargin.bottom - + pfd->mBounds.height; + } + break; + case VALIGN_OTHER: + pfd->mBounds.y += baselineY; + break; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d\n", pfd->mBounds.y); +#endif + if (span) { + nscoord distanceFromTop = pfd->mBounds.y - mTopEdge; + PlaceTopBottomFrames(span, distanceFromTop, lineHeight); + } + pfd = pfd->mNext; + } + + // Fill in returned line-box and max-element-size data + aLineBoxResult.x = psd->mLeftEdge; + aLineBoxResult.y = mTopEdge; + aLineBoxResult.width = psd->mX - psd->mLeftEdge; + aLineBoxResult.height = lineHeight; + aMaxElementSizeResult.width = maxElementWidth; + aMaxElementSizeResult.height = maxElementHeight; + + // Undo root-span mFrame pointer to prevent brane damage later on... + mRootSpan->mFrame = nsnull; +} + +void +nsLineLayout::PlaceTopBottomFrames(PerSpanData* psd, + nscoord aDistanceFromTop, + nscoord aLineHeight) +{ + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + PerSpanData* span = pfd->mSpan; + switch (pfd->mVerticalAlign) { + case VALIGN_TOP: + if (span) { + pfd->mBounds.y = -aDistanceFromTop - pfd->mBorderPadding.top + + span->mTopLeading; + } + else { + pfd->mBounds.y = -aDistanceFromTop + pfd->mMargin.top; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d dTop=%d [bp.top=%d topLeading=%d]\n", + pfd->mBounds.y, aDistanceFromTop, + span ? pfd->mBorderPadding.top : 0, + span ? span->mTopLeading : 0); +#endif + break; + case VALIGN_BOTTOM: + if (span) { + // Compute bottom leading + pfd->mBounds.y = -aDistanceFromTop + aLineHeight - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + span->mBottomLeading; + } + else { + pfd->mBounds.y = -aDistanceFromTop + aLineHeight - + pfd->mMargin.bottom - pfd->mBounds.height; + } + pfd->mFrame->SetRect(pfd->mBounds); +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, pfd->mFrame); + printf(": y=%d\n", pfd->mBounds.y); +#endif + break; + } + if (span) { + nscoord distanceFromTop = distanceFromTop + pfd->mBounds.y; + PlaceTopBottomFrames(span, distanceFromTop, aLineHeight); + } + pfd = pfd->mNext; + } +} + +// Vertically place frames within a given span. Note: this doesn't +// place top/bottom aligned frames as those have to wait until the +// entire line box height is known. This is called after the span +// frame has finished being reflowed so that we know its height. +void +nsLineLayout::VerticalAlignFrames(PerSpanData* psd) +{ + // Get parent frame info + PerFrameData* parentPFD = psd->mFrame; + nsIFrame* parentFrame = parentPFD->mFrame; + + // Get the parent frame's font for all of the frames in this span + const nsStyleFont* parentFont; + parentFrame->GetStyleData(eStyleStruct_Font, + (const nsStyleStruct*&)parentFont); + nsIRenderingContext* rc = mBlockReflowState->rendContext; + rc->SetFont(parentFont->mFont); + nsIFontMetrics* fm; + rc->GetFontMetrics(fm); + + + // Setup baselineY, minY, and maxY + nscoord baselineY, minY, maxY; + if (psd == mRootSpan) { + // Use a zero baselineY since we don't yet know where the baseline + // will be (until we know how tall the line is; then we will + // know). In addition, use extreme values for the minY and maxY + // values so that only the child frames will impact their values + // (since these are children of the block, there is no span box to + // provide initial values). + baselineY = 0; + minY = 0; + maxY = 0; +#ifdef NOISY_VERTICAL_ALIGN + nsFrame::ListTag(stdout, parentFrame); + printf(": pass1 valign frames: topEdge=%d minLineHeight=%d\n", + mTopEdge, mMinLineHeight); +#endif + } + else if (0 != parentPFD->mBounds.height) { + // Compute the logical height for this span. Also compute the top + // leading. + nscoord logicalHeight = + nsHTMLReflowState::CalcLineHeight(mPresContext, parentFrame); + nscoord contentHeight = parentPFD->mBounds.height - + parentPFD->mBorderPadding.top - parentPFD->mBorderPadding.bottom; + nscoord leading = logicalHeight - contentHeight; + psd->mTopLeading = leading / 2; + psd->mBottomLeading = leading - psd->mTopLeading; + psd->mLogicalHeight = logicalHeight; + + // The initial values for the min and max Y values are in the spans + // coordinate space, and cover the logical height of the span. If + // there are child frames in this span that stick out of this area + // then the minY and maxY are updated by the amount of logical + // height that is outside this range. + minY = parentPFD->mBorderPadding.top - psd->mTopLeading; + maxY = minY + psd->mLogicalHeight; + + // This is the distance from the top edge of the parents visual + // box to the baseline. + nscoord parentAscent; + fm->GetMaxAscent(parentAscent); + baselineY = parentAscent + parentPFD->mBorderPadding.top; +#ifdef NOISY_VERTICAL_ALIGN + nsFrame::ListTag(stdout, parentFrame); + printf(": baseLine=%d logicalHeight=%d topLeading=%d h=%d bp=%d,%d\n", + baselineY, logicalHeight, psd->mTopLeading, + parentPFD->mBounds.height, + parentPFD->mBorderPadding.top, parentPFD->mBorderPadding.bottom); +#endif + } + else { + // When a span container is zero height it means that all of its + // kids are zero height as well. + psd->mMinY = 0; + psd->mMaxY = 0; + psd->mTopLeading = 0; + psd->mBottomLeading = 0; + psd->mLogicalHeight = 0; +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> [empty line]\n"); +#endif + return; + } + + nscoord maxTopBoxHeight = 0; + nscoord maxBottomBoxHeight = 0; + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nsIFrame* frame = pfd->mFrame; + + // Compute the logical height of the frame + nscoord logicalHeight; + nscoord topLeading; + PerSpanData* frameSpan = pfd->mSpan; + if (frameSpan) { + // For span frames the logical-height and top-leading was + // pre-computed when the span was reflowed. + logicalHeight = frameSpan->mLogicalHeight; + topLeading = frameSpan->mTopLeading; + } + else { + // For other elements the logical height is the same as the + // frames height plus its margins. + logicalHeight = pfd->mBounds.height + pfd->mMargin.top + + pfd->mMargin.bottom; + topLeading = 0; + } + + // Get vertical-align property + const nsStyleText* textStyle; + frame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)textStyle); + nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit(); + if (eStyleUnit_Inherit == verticalAlignUnit) { + printf("XXX: vertical-align: inherit not implemented for "); + nsFrame::ListTag(stdout, frame); + printf("\n"); + } + PRUint8 verticalAlignEnum; + nscoord parentAscent, parentDescent, parentXHeight; + nscoord parentSuperscript, parentSubscript; + nscoord coordOffset, percentOffset, elementLineHeight; + nscoord revisedBaselineY; + switch (verticalAlignUnit) { + case eStyleUnit_Enumerated: + default: + if (eStyleUnit_Enumerated == verticalAlignUnit) { + verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue(); + } + else { + verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BASELINE; + } + switch (verticalAlignEnum) { + default: + case NS_STYLE_VERTICAL_ALIGN_BASELINE: + // The elements baseline is aligned with the baseline of + // the parent. + if (frameSpan) { + // XXX explain + pfd->mBounds.y = baselineY - pfd->mAscent; + } + else { + // For non-span elements the borders, padding and + // margins are significant. Use the visual box height + // and the bottom margin as the distance off of the + // baseline. + pfd->mBounds.y = baselineY - pfd->mAscent - pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_SUB: + // Lower the baseline of the box to the subscript offset + // of the parent's box. This is identical to the baseline + // alignment except for the addition of the subscript + // offset to the baseline Y. + fm->GetSubscriptOffset(parentSubscript); + revisedBaselineY = baselineY + parentSubscript; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_SUPER: + // Raise the baseline of the box to the superscript offset + // of the parent's box. This is identical to the baseline + // alignment except for the subtraction of the superscript + // offset to the baseline Y. + fm->GetSuperscriptOffset(parentSuperscript); + revisedBaselineY = baselineY - parentSuperscript; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TOP: + pfd->mVerticalAlign = VALIGN_TOP; + if (logicalHeight > maxTopBoxHeight) { + maxTopBoxHeight = logicalHeight; + } + break; + + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: + pfd->mVerticalAlign = VALIGN_BOTTOM; + if (logicalHeight > maxBottomBoxHeight) { + maxBottomBoxHeight = logicalHeight; + } + break; + + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: + // Align the midpoint of the frame with 1/2 the parents + // x-height above the baseline. + fm->GetXHeight(parentXHeight); + if (frameSpan) { + pfd->mBounds.y = baselineY - + (parentXHeight + pfd->mBounds.height)/2; + } + else { + pfd->mBounds.y = baselineY - (parentXHeight + logicalHeight)/2 + + pfd->mMargin.top; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP: + // The top of the logical box is aligned with the top of + // the parent elements text. + fm->GetMaxAscent(parentAscent); + if (frameSpan) { + pfd->mBounds.y = baselineY - parentAscent - + pfd->mBorderPadding.top + frameSpan->mTopLeading; + } + else { + pfd->mBounds.y = baselineY - parentAscent + pfd->mMargin.top; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM: + // The bottom of the logical box is aligned with the + // bottom of the parent elements text. + fm->GetMaxDescent(parentDescent); + if (frameSpan) { + pfd->mBounds.y = baselineY + parentDescent - + pfd->mBounds.height + pfd->mBorderPadding.bottom - + frameSpan->mBottomLeading; + } + else { + pfd->mBounds.y = baselineY + parentDescent - + pfd->mBounds.height - pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + } + break; + + case eStyleUnit_Coord: + // According to the CSS2 spec (10.8.1), a positive value + // "raises" the box by the given distance while a negative value + // "lowers" the box by the given distance (with zero being the + // baseline). Since Y coordinates increase towards the bottom of + // the screen we reverse the sign. + coordOffset = textStyle->mVerticalAlign.GetCoordValue(); + revisedBaselineY = baselineY - coordOffset; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + + case eStyleUnit_Percent: + // Similar to a length value (eStyleUnit_Coord) except that the + // percentage is a function of the elements line-height value. + elementLineHeight = + nsHTMLReflowState::CalcLineHeight(mPresContext, frame); + percentOffset = nscoord( + textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight + ); + revisedBaselineY = baselineY - percentOffset; + if (frameSpan) { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent; + } + else { + pfd->mBounds.y = revisedBaselineY - pfd->mAscent - + pfd->mMargin.bottom; + } + pfd->mVerticalAlign = VALIGN_OTHER; + break; + } + + // Update minY/maxY for frames that we just placed + if (pfd->mVerticalAlign == VALIGN_OTHER) { + nscoord yTop, yBottom; + if (frameSpan) { + // For spans that were are now placing, use their position + // plus their already computed min-Y and max-Y values for + // computing yTop and yBottom. + yTop = pfd->mBounds.y + frameSpan->mMinY; + yBottom = pfd->mBounds.y + frameSpan->mMaxY; + } + else { + yTop = pfd->mBounds.y - pfd->mMargin.top; + yBottom = yTop + logicalHeight; + } + if (yTop < minY) minY = yTop; + if (yBottom > maxY) maxY = yBottom; +#ifdef NOISY_VERTICAL_ALIGN + printf(" "); + nsFrame::ListTag(stdout, frame); + printf(": raw: a=%d d=%d h=%d bp=%d,%d logical: h=%d leading=%d y=%d minY=%d maxY=%d\n", + pfd->mAscent, pfd->mDescent, pfd->mBounds.height, + pfd->mBorderPadding.top, pfd->mBorderPadding.bottom, + logicalHeight, + pfd->mSpan ? topLeading : 0, + pfd->mBounds.y, minY, maxY); +#endif + if (psd != mRootSpan) { + frame->SetRect(pfd->mBounds); + } + } + pfd = pfd->mNext; + } + NS_RELEASE(fm); + psd->mMinY = minY; + psd->mMaxY = maxY; +#ifdef NOISY_VERTICAL_ALIGN + printf(" ==> minY=%d maxY=%d delta=%d maxBoxHeight=%d\n", + minY, maxY, maxY - minY, maxBoxHeight); +#endif + if (maxTopBoxHeight > mMaxTopBoxHeight) { + mMaxTopBoxHeight = maxTopBoxHeight; + } + if (maxBottomBoxHeight > mMaxBottomBoxHeight) { + mMaxBottomBoxHeight = maxBottomBoxHeight; + } +} + +void +nsLineLayout::TrimTrailingWhiteSpace(nsRect& aLineBounds) +{ +} + +void +nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify) +{ + PerSpanData* psd = mRootSpan; + nscoord availWidth = psd->mRightEdge; + if (NS_UNCONSTRAINEDSIZE == availWidth) { + // Don't bother horizontal aligning on pass1 table reflow +#ifdef REALLY_NOISY_HORIZONTAL_ALIGN + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": skipping horizontal alignment in pass1 table reflow\n"); +#endif + return; + } + availWidth -= psd->mLeftEdge; + nscoord remainingWidth = availWidth - aLineBounds.width; +#ifdef REALLY_NOISY_HORIZONTAL_ALIGN + nsFrame::ListTag(stdout, mBlockReflowState->frame); + printf(": availWidth=%d lineWidth=%d delta=%d\n", + availWidth, aLineBounds.width, remainingWidth); +#endif + if (remainingWidth > 0) { + nscoord dx = 0; + switch (mTextAlign) { + case NS_STYLE_TEXT_ALIGN_DEFAULT: + if (NS_STYLE_DIRECTION_LTR == mDirection) { + // default alignment for left-to-right is left so do nothing + break; + } + // Fall through to align right case for default alignment + // used when the direction is right-to-left. + + case NS_STYLE_TEXT_ALIGN_RIGHT: + dx = remainingWidth; + break; + + case NS_STYLE_TEXT_ALIGN_LEFT: + break; + + case NS_STYLE_TEXT_ALIGN_JUSTIFY: + // If this is not the last line then go ahead and justify the + // frames in the line. If it is the last line then if the + // direction is right-to-left then we right-align the frames. + if (aAllowJustify) { + break; + } + else if (NS_STYLE_DIRECTION_RTL == mDirection) { + // right align the frames + dx = remainingWidth;; + } + break; + + case NS_STYLE_TEXT_ALIGN_CENTER: + dx = remainingWidth / 2; + break; + } + if (0 != dx) { + PerFrameData* pfd = psd->mFirstFrame; + while (nsnull != pfd) { + pfd->mBounds.x += dx; + pfd->mFrame->SetRect(pfd->mBounds); + pfd = pfd->mNext; + } + } + } +} + +void +nsLineLayout::RelativePositionFrames(nsRect& aCombinedArea) +{ + RelativePositionFrames(mRootSpan, aCombinedArea); +} + +void +nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea) +{ + nsPoint origin; + nsRect spanCombinedArea; + PerFrameData* pfd; + + nscoord x0, y0, x1, y1; + if (nsnull != psd->mFrame) { + // The minimum combined area for the frames in a span covers the + // entire span frame. + pfd = psd->mFrame; + x0 = 0; + y0 = 0; + x1 = pfd->mBounds.width; + y1 = pfd->mBounds.height; + } + else { + // The minimum combined area for the frames that are direct + // children of the block starts at the upper left corner of the + // line but has no width or height. + x1 = x0 = psd->mLeftEdge; + y1 = y0 = mTopEdge; + } + + pfd = psd->mFirstFrame; + while (nsnull != pfd) { + nscoord x = pfd->mBounds.x; + nscoord y = pfd->mBounds.y; + + // Adjust the origin of the frame + if (pfd->mRelativePos) { + nsIFrame* frame = pfd->mFrame; + frame->GetOrigin(origin); + // XXX what about right and bottom? + nscoord dx = pfd->mOffsets.left; + nscoord dy = pfd->mOffsets.top; + frame->MoveTo(origin.x + dx, origin.y + dy); + x += dx; + y += dy; + } + + // Note: the combined area of a child is in its coordinate + // system. We adjust the childs combined area into our coordinate + // system before computing the aggregated value by adding in + // x and y which were computed above. + nsRect* r = &pfd->mCombinedArea; + if (pfd->mSpan) { + // Compute a new combined area for the child span before + // aggregating it into our combined area. + r = &spanCombinedArea; + RelativePositionFrames(pfd->mSpan, spanCombinedArea); + } + + nscoord xl = x + r->x; + nscoord xr = x + r->XMost(); + if (xl < x0) x0 = xl; + if (xr > x1) x1 = xr; + nscoord yt = y + r->y; + nscoord yb = y + r->YMost(); + if (yt < y0) y0 = yt; + if (yb > y1) y1 = yb; + + pfd = pfd->mNext; + } + + // Compute aggregated combined area + aCombinedArea.x = x0; + aCombinedArea.y = y0; + aCombinedArea.width = x1 - x0; + aCombinedArea.height = y1 - y0; + + // If we just computed a spans combined area, we need to update its + // NS_FRAME_OUTSIDE_CHILDREN bit.. + if (nsnull != psd->mFrame) { + pfd = psd->mFrame; + nsIFrame* frame = pfd->mFrame; + nsFrameState oldState; + frame->GetFrameState(&oldState); + nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; + if ((x0 < 0) || (y0 < 0) || + (x1 > pfd->mBounds.width) || (y1 > pfd->mBounds.height)) { + newState |= NS_FRAME_OUTSIDE_CHILDREN; + } + if (newState != oldState) { + frame->SetFrameState(newState); + } + } +} + +void +nsLineLayout::ForgetWordFrame(nsIFrame* aFrame) +{ + NS_ASSERTION((void*)aFrame == mWordFrames[0], "forget-word-frame"); + if (0 != mWordFrames.Count()) { + mWordFrames.RemoveElementAt(0); } - return nsnull; } nsIFrame* @@ -164,56 +1810,41 @@ nsLineLayout::FindNextText(nsIFrame* aFrame) return nsnull; } -PRBool -nsLineLayout::IsNextWordFrame(nsIFrame* aFrame) +nsresult +nsLineLayout::AddText(nsIFrame* aTextFrame) { - if (0 != mWordFrames.Count()) { - nsIFrame* next = (nsIFrame*) mWordFrames[0]; - return next == aFrame; + if (nsnull == mNewTextRun) { + mNewTextRun = new nsTextRun(); + if (nsnull == mNewTextRun) { + return NS_ERROR_OUT_OF_MEMORY; + } + *mTextRunP = mNewTextRun; + mTextRunP = &mNewTextRun->mNext; } - return PR_FALSE; -} - -PRBool -nsLineLayout::IsLastWordFrame(nsIFrame* aFrame) -{ - PRInt32 n = mWordFrames.Count(); - if (0 != n) { - nsIFrame* next = (nsIFrame*) mWordFrames[0]; - return (next == aFrame) && (1 == n); + mNewTextRun->mArray.AppendElement(aTextFrame); +#ifdef DEBUG_ADD_TEXT + PRInt32 n = mNewTextRun->mArray.Count(); + for (PRInt32 i = 0; i < n - 1; i++) { + NS_ASSERTION(mNewTextRun->mArray[i] != (void*)aTextFrame, "yikes"); } - return PR_FALSE; +#endif + return NS_OK;/* XXX */ } void -nsLineLayout::ForgetWordFrame(nsIFrame* aFrame) +nsLineLayout::EndTextRun() { - NS_ASSERTION((void*)aFrame == mWordFrames[0], "forget-word-frame"); - if (0 != mWordFrames.Count()) { - mWordFrames.RemoveElementAt(0); - } + mNewTextRun = nsnull; } -// XXX move this somewhere else!!! -PRBool -nsLineLayout::TreatFrameAsBlock(const nsStyleDisplay* aDisplay, - const nsStylePosition* aPosition) +nsTextRun* +nsLineLayout::TakeTextRuns() { - if (NS_STYLE_POSITION_ABSOLUTE == aPosition->mPosition) { - return PR_FALSE; - } - if (NS_STYLE_FLOAT_NONE != aDisplay->mFloats) { - return PR_FALSE; - } - switch (aDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - case NS_STYLE_DISPLAY_RUN_IN: - case NS_STYLE_DISPLAY_COMPACT: - case NS_STYLE_DISPLAY_TABLE: - return PR_TRUE; - } - return PR_FALSE; + nsTextRun* result = mTextRuns; + mTextRuns = nsnull; + mTextRunP = &mTextRuns; + mNewTextRun = nsnull; + return result; } PRBool @@ -223,24 +1854,19 @@ nsLineLayout::TreatFrameAsBlock(nsIFrame* aFrame) const nsStylePosition* position; aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); aFrame->GetStyleData(eStyleStruct_Position,(const nsStyleStruct*&) position); - return TreatFrameAsBlock(display, position); -} - -void -nsLineLayout::UpdateInlines(nscoord aX, nscoord aY, - nscoord aWidth, nscoord aHeight, - PRBool aIsLeftFloater) -{ - PRInt32 i, n = mInlineStack.Count(); - for (i = 0; i < n; i++) { - nsInlineReflow* ir = (nsInlineReflow*) mInlineStack[i]; - ir->UpdateBand(aX, aY, aWidth, aHeight, aIsLeftFloater); - - // After the first inline is updated the remainder are relative to - // their parent therefore zap the x,y coordinates. - - // XXX border/padding adjustments need to be re-applied for inlines - aX = 0; - aY = 0; + if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { + return PR_FALSE; } + if (NS_STYLE_FLOAT_NONE != display->mFloats) { + return PR_FALSE; + } + switch (display->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + case NS_STYLE_DISPLAY_RUN_IN: + case NS_STYLE_DISPLAY_COMPACT: + case NS_STYLE_DISPLAY_TABLE: + return PR_TRUE; + } + return PR_FALSE; } diff --git a/mozilla/layout/html/base/src/nsLineLayout.h b/mozilla/layout/html/base/src/nsLineLayout.h index 3e16f842d76..1542bcd7dd5 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.h +++ b/mozilla/layout/html/base/src/nsLineLayout.h @@ -19,132 +19,28 @@ #ifndef nsLineLayout_h___ #define nsLineLayout_h___ -#include "nsIFrame.h" +#include "nsFrame.h" #include "nsVoidArray.h" #include "nsTextReflow.h" +class nsISpaceManager; class nsBlockReflowState; -class nsInlineReflow; class nsPlaceholderFrame; -struct nsStyleDisplay; -struct nsStylePosition; -struct nsStyleSpacing; - -// XXX rename to nsLineReflow - -//---------------------------------------------------------------------- +struct nsStyleText; class nsLineLayout { public: nsLineLayout(nsIPresContext& aPresContext, - nsISpaceManager* aSpaceManager); + nsISpaceManager* aSpaceManager, + const nsHTMLReflowState* aOuterReflowState, + PRBool aComputeMaxElementSize); + nsLineLayout(nsIPresContext& aPresContext); ~nsLineLayout(); - void Init(nsBlockReflowState* aReflowState) {/* XXX ctor arg really */ - mBlockReflowState = aReflowState; + void Init(nsBlockReflowState* aState) { + mBlockRS = aState; } - // Prepare this line-layout for the reflow of a new line - void Reset() { - mTotalPlacedFrames = 0; - mColumn = 0; - mEndsInWhiteSpace = PR_TRUE; - mUnderstandsWhiteSpace = PR_FALSE; - mBRFrame = nsnull; - mPlacedFrames.Clear(); - ForgetWordFrames(); - mFirstLetterStyleOK = PR_FALSE; - mPass2VAlignCount = 0; - } - - // Record the prescence of a frame that needs pass2 vertical-align - // handling. - void RecordPass2VAlignFrame() { - mPass2VAlignCount++; - } - - PRBool NeedPass2VAlign() const { - return 0 != mPass2VAlignCount; - } - - // Add to the placed-frame count - void AddPlacedFrame(nsIFrame* aFrame) { - mTotalPlacedFrames++; - mPlacedFrames.AppendElement(aFrame); - } - - // Get the placed-frame count - PRInt32 GetPlacedFrames() const { - return mTotalPlacedFrames; - } - - const nsVoidArray& PlacedFrames() const { - return mPlacedFrames; - } - - void SetBRFrame(nsIFrame* aFrame) { - mBRFrame = aFrame; - } - - nsIFrame* GetBRFrame() const { - return mBRFrame; - } - - void PushInline(nsInlineReflow* aInlineReflow) { - mInlineStack.AppendElement(aInlineReflow); - } - - void PopInline() { - PRInt32 n = mInlineStack.Count(); - if (n > 0) { - mInlineStack.RemoveElementAt(n - 1); - } - } - - void UpdateInlines(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, - PRBool aPlacedLeftFloater); - - // Reset the text-run information in preparation for a FindTextRuns - void ResetTextRuns(); - - // Add another piece of text to a text-run during FindTextRuns. - // Note: continuation frames must NOT add themselves; just the - // first-in-flow - nsresult AddText(nsIFrame* aTextFrame); - - // Close out a text-run during FindTextRuns. - void EndTextRun(); - - // This returns the first nsTextRun found during a - // FindTextRuns. The internal text-run state is reset. - nsTextRun* TakeTextRuns(); - - void SetReflowTextRuns(nsTextRun* aTextRuns) { - mReflowTextRuns = aTextRuns; - } - - nsIFrame* FindNextText(nsIFrame* aFrame); - - nsTextRun* FindTextRunFor(nsIFrame* aFrame); - - void RecordWordFrame(nsIFrame* aWordFrame) { - mWordFrames.AppendElement(aWordFrame); - } - - void ForgetWordFrames() { - mWordFrames.Clear(); - } - - PRBool IsNextWordFrame(nsIFrame* aFrame); - - PRBool InWord() { - return 0 != mWordFrames.Count(); - } - - PRBool IsLastWordFrame(nsIFrame* aFrame); - - void ForgetWordFrame(nsIFrame* aFrame); - PRInt32 GetColumn() { return mColumn; } @@ -153,7 +49,7 @@ public: mColumn = aNewColumn; } - void NextLine() { + void AdvanceToNextLine() { mLineNumber++; } @@ -161,33 +57,63 @@ public: return mLineNumber; } - static PRBool TreatFrameAsBlock(const nsStyleDisplay* aDisplay, - const nsStylePosition* aPosition); + void BeginLineReflow(nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight, + PRBool aIsTopOfPage); - static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + void EndLineReflow(); - // -------------------------------------------------- + void UpdateBand(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + PRBool aPlacedLeftFloater); - void InitFloater(nsPlaceholderFrame* aFrame); + nsresult BeginSpan(nsIFrame* aFrame, + const nsHTMLReflowState* aSpanReflowState, + nscoord aLeftEdge, + nscoord aRightEdge); - void AddFloater(nsPlaceholderFrame* aFrame); + void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, + nsSize* aMaxElementSize); - nsIPresContext& mPresContext; - nsISpaceManager* mSpaceManager; - nsBlockReflowState* mBlockReflowState; + PRInt32 GetCurrentSpanCount() const; - PRBool mListPositionOutside; - PRInt32 mLineNumber; - PRInt32 mColumn; - - void SetUnderstandsWhiteSpace(PRBool aSetting) { - mUnderstandsWhiteSpace = aSetting; + void SplitLineTo(PRInt32 aNewCount); + + PRBool IsZeroHeight(); + + nsresult ReflowFrame(nsIFrame* aFrame, + nsIFrame** aNextRCFrame, + nsReflowStatus& aReflowStatus); + + + nscoord GetCarriedOutTopMargin() const { + return mCurrentSpan->mLastFrame->mCarriedOutTopMargin; } - PRBool GetUnderstandsWhiteSpace() const { - return mUnderstandsWhiteSpace; + nscoord GetCarriedOutBottomMargin() const { + return mCurrentSpan->mLastFrame->mCarriedOutBottomMargin; } + nsresult AddBulletFrame(nsIFrame* aFrame, + const nsHTMLReflowMetrics& aMetrics); + + void RemoveBulletFrame(nsIFrame* aFrame) { + PushFrame(aFrame); + } + + void VerticalAlignFrames(nsRect& aLineBoxResult, + nsSize& aMaxElementSizeResult); + + void TrimTrailingWhiteSpace(nsRect& aLineBounds); + + void HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify); + + void RelativePositionFrames(nsRect& aCombinedArea); + + //---------------------------------------- + + // Support methods for white-space compression and word-wrapping + // during line reflow + void SetEndsInWhiteSpace(PRBool aState) { mEndsInWhiteSpace = aState; } @@ -196,6 +122,51 @@ public: return mEndsInWhiteSpace; } + void SetUnderstandsWhiteSpace(PRBool aSetting) { + mUnderstandsWhiteSpace = aSetting; + } + + void RecordWordFrame(nsIFrame* aWordFrame) { + mWordFrames.AppendElement(aWordFrame); + } + + PRBool InWord() const { + return 0 != mWordFrames.Count(); + } + + void ForgetWordFrame(nsIFrame* aFrame); + + void ForgetWordFrames() { + mWordFrames.Clear(); + } + + nsIFrame* FindNextText(nsIFrame* aFrame); + + PRBool LineIsEmpty() const { + return 0 == mTotalPlacedFrames; + } + + //---------------------------------------- + + // Inform the line-layout engine about the presence of a BR frame + // XXX get rid of this: use get-frame-type? + void SetBRFrame(nsIFrame* aFrame) { + mBRFrame = aFrame; + } + + // Return the line's BR frame if any + nsIFrame* GetBRFrame() const { + return mBRFrame; + } + + //---------------------------------------- + // Inform the line-layout about the presence of a floating frame + // XXX get rid of this: use get-frame-type? + void InitFloater(nsPlaceholderFrame* aFrame); + void AddFloater(nsPlaceholderFrame* aFrame); + + //---------------------------------------- + PRBool GetFirstLetterStyleOK() const { return mFirstLetterStyleOK; } @@ -204,29 +175,185 @@ public: mFirstLetterStyleOK = aSetting; } -protected: - nsIFrame* mBRFrame; + //---------------------------------------- + // Text run usage methods. These methods are using during reflow to + // track the current text run and to advance through text runs. + void SetReflowTextRuns(nsTextRun* aTextRuns) { + mReflowTextRuns = aTextRuns; + } + + //---------------------------------------- + + static PRBool TreatFrameAsBlock(nsIFrame* aFrame); + + //---------------------------------------- + + // XXX Move this out of line-layout; make some little interface to + // deal with it... + + // Add another piece of text to a text-run during FindTextRuns. + // Note: continuation frames must NOT add themselves; just the + // first-in-flow + nsresult AddText(nsIFrame* aTextFrame); + + // Close out a text-run during FindTextRuns. + void EndTextRun(); + + // This returns the first nsTextRun found during a FindTextRuns. The + // internal text-run state is reset. + nsTextRun* TakeTextRuns(); + + nsIPresContext& mPresContext; + +protected: + // This state is constant for a given block frame doing line layout + nsISpaceManager* mSpaceManager; + const nsStyleText* mStyleText; + const nsHTMLReflowState* mBlockReflowState; + nsBlockReflowState* mBlockRS;/* XXX hack! */ + nscoord mMinLineHeight; + PRBool mComputeMaxElementSize; + PRBool mNoWrap; + PRUint8 mTextAlign; + PRUint8 mDirection; + + // This state varies during the reflow of a line + nsIFrame* mBRFrame; + PRInt32 mLineNumber; + PRInt32 mColumn; PRBool mEndsInWhiteSpace; PRBool mUnderstandsWhiteSpace; PRBool mFirstLetterStyleOK; - PRInt32 mPass2VAlignCount; - + PRBool mIsTopOfPage; + PRBool mWasInWord; + PRBool mCanBreakBeforeFrame; + PRBool mUpdatedBand; + PRUint8 mPlacedFloaters; PRInt32 mTotalPlacedFrames; - nsVoidArray mPlacedFrames; - nsVoidArray mWordFrames; - nsVoidArray mInlineStack; + nscoord mTopEdge; + nscoord mBottomEdge; + nscoord mMaxTopBoxHeight; + nscoord mMaxBottomBoxHeight; - // These slots are used during FindTextRuns + nsTextRun* mReflowTextRuns; + nsTextRun* mTextRun; + + // Per-frame data recorded by the line-layout reflow logic. This + // state is the state needed to post-process the line after reflow + // has completed (vertical alignment, horizontal alignment, + // justification and relative positioning). + struct PerSpanData; + struct PerFrameData { + // link to next/prev frame in same span + PerFrameData* mNext; + PerFrameData* mPrev; + + // pointer to child span data if this is an inline container frame + PerSpanData* mSpan; + + // The frame and its type + nsIFrame* mFrame; + nsCSSFrameType mFrameType; + + // From metrics + nscoord mAscent, mDescent; + nsRect mBounds; + nsSize mMaxElementSize; + nsRect mCombinedArea; + nscoord mCarriedOutTopMargin; + nscoord mCarriedOutBottomMargin; + + // From reflow-state + nsMargin mMargin; + nsMargin mBorderPadding; + nsMargin mOffsets; + PRBool mRelativePos; + + // Other state we use + PRUint8 mVerticalAlign; + }; + PerFrameData mFrameDataBuf[20]; + PerFrameData* mFrameFreeList; + + struct PerSpanData { + PerSpanData* mNext; + PerSpanData* mPrev; + PerSpanData* mParent; + PerFrameData* mFrame; + PerFrameData* mFirstFrame; + PerFrameData* mLastFrame; + + const nsHTMLReflowState* mReflowState; + nscoord mLeftEdge; + nscoord mX; + nscoord mRightEdge; + + nscoord mTopLeading, mBottomLeading; + nscoord mLogicalHeight; + nscoord mMinY, mMaxY; + + void AppendFrame(PerFrameData* pfd) { + if (nsnull == mLastFrame) { + mFirstFrame = pfd; + } + else { + mLastFrame->mNext = pfd; + pfd->mPrev = mLastFrame; + } + mLastFrame = pfd; + } + }; + PerSpanData mSpanDataBuf[20]; + PerSpanData* mSpanFreeList; + PerSpanData* mRootSpan; + PerSpanData* mLastSpan; + PerSpanData* mCurrentSpan; + PRInt32 mSpanDepth; + + // XXX These slots are used ONLY during FindTextRuns nsTextRun* mTextRuns; nsTextRun** mTextRunP; nsTextRun* mNewTextRun; - // These slots are used during InlineReflow - nsTextRun* mReflowTextRuns; - nsTextRun* mTextRun; + nsresult NewPerFrameData(PerFrameData** aResult); + + nsresult NewPerSpanData(PerSpanData** aResult); + + void FreeSpan(PerSpanData* psd); + + PRBool InBlockContext() const { + return mSpanDepth == 0; + } + + void PushFrame(nsIFrame* aFrame); + + void ApplyLeftMargin(PerFrameData* pfd, + nsHTMLReflowState& aReflowState); + + PRBool CanPlaceFrame(PerFrameData* pfd, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); + + void PlaceFrame(PerFrameData* pfd, + nsHTMLReflowMetrics& aMetrics); + + void UpdateFrames(); + + void VerticalAlignFrames(PerSpanData* psd); + + void PlaceTopBottomFrames(PerSpanData* psd, + nscoord aDistanceFromTop, + nscoord aLineHeight); + + void RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea); + +#ifdef DEBUG + void DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent); +#endif }; #endif /* nsLineLayout_h___ */