From 55b2683b922f5ca494d7861b64cd66cefd680d31 Mon Sep 17 00:00:00 2001 From: kipp Date: Thu, 25 Jun 1998 16:33:10 +0000 Subject: [PATCH] New and improved (?) line layout git-svn-id: svn://10.0.0.236/trunk@4495 18797224-902f-48f8-a5cc-f745e15eee43 --- .../content/html/style/src/nsCSSLayout.cpp | 4 +- mozilla/layout/Makefile | 2 +- mozilla/layout/base/src/nsContainerFrame.cpp | 88 +- mozilla/layout/base/src/nsContainerFrame.h | 49 +- mozilla/layout/base/src/nsFrame.cpp | 6 +- mozilla/layout/base/src/nsFrame.h | 24 +- mozilla/layout/base/src/nsSplittableFrame.cpp | 2 + mozilla/layout/build/makefile.win | 2 + .../layout/css/layout/src/nsCSSBlockFrame.cpp | 290 ++- .../layout/css/layout/src/nsCSSBlockFrame.h | 14 +- .../css/layout/src/nsCSSContainerFrame.h | 17 +- .../css/layout/src/nsCSSInlineFrame.cpp | 418 ++-- .../layout/css/layout/src/nsCSSInlineFrame.h | 15 +- .../css/layout/src/nsCSSInlineLayout.cpp | 68 +- .../layout/css/layout/src/nsCSSInlineLayout.h | 11 +- .../layout/css/layout/src/nsCSSLineLayout.cpp | 1 + .../layout/css/layout/src/nsCSSLineLayout.h | 14 + mozilla/layout/generic/nsBlockFrame.cpp | 1961 ----------------- mozilla/layout/generic/nsBlockFrame.h | 313 --- mozilla/layout/generic/nsBlockReflowState.cpp | 1961 ----------------- mozilla/layout/generic/nsBlockReflowState.h | 1961 ----------------- .../layout/generic/nsHTMLContainerFrame.cpp | 93 +- mozilla/layout/generic/nsHTMLContainerFrame.h | 6 +- mozilla/layout/generic/nsInlineFrame.cpp | 1288 ----------- mozilla/layout/generic/nsLeafFrame.cpp | 1 + mozilla/layout/generic/nsLineLayout.cpp | 1695 -------------- mozilla/layout/generic/nsLineLayout.h | 248 --- mozilla/layout/generic/nsPlaceholderFrame.cpp | 8 +- mozilla/layout/html/base/src/Makefile | 2 - .../layout/html/base/src/deadnsInlineFrame.h | 102 - mozilla/layout/html/base/src/makefile.win | 21 +- mozilla/layout/html/base/src/nsBRPart.cpp | 96 +- mozilla/layout/html/base/src/nsBlockFrame.cpp | 1961 ----------------- mozilla/layout/html/base/src/nsBlockFrame.h | 313 --- .../html/base/src/nsBlockReflowState.cpp | 1961 ----------------- .../layout/html/base/src/nsBlockReflowState.h | 1961 ----------------- mozilla/layout/html/base/src/nsBodyFrame.cpp | 42 +- mozilla/layout/html/base/src/nsHTMLBullet.cpp | 260 ++- .../layout/html/base/src/nsHTMLContainer.cpp | 9 +- .../html/base/src/nsHTMLContainerFrame.cpp | 93 +- .../html/base/src/nsHTMLContainerFrame.h | 6 +- mozilla/layout/html/base/src/nsHTMLIIDs.cpp | 14 +- mozilla/layout/html/base/src/nsHTMLIIDs.h | 8 +- .../html/base/src/nsIFloaterContainer.h | 29 +- .../layout/html/base/src/nsInlineFrame.cpp | 1288 ----------- mozilla/layout/html/base/src/nsLeafFrame.cpp | 1 + mozilla/layout/html/base/src/nsLineLayout.cpp | 1695 -------------- mozilla/layout/html/base/src/nsLineLayout.h | 248 --- .../html/base/src/nsPlaceholderFrame.cpp | 8 +- mozilla/layout/html/base/src/nsRootPart.cpp | 46 +- .../layout/html/base/src/nsScrollFrame.cpp | 19 +- mozilla/layout/html/base/src/nsSpacerPart.cpp | 97 +- .../layout/html/base/src/nsTextContent.cpp | 644 ++---- .../layout/html/document/src/nsHTMLIFrame.cpp | 1 + mozilla/layout/html/document/src/ua.css | 2 +- mozilla/layout/html/forms/src/Makefile | 3 +- mozilla/layout/html/forms/src/makefile.win | 8 +- mozilla/layout/html/forms/src/nsInputFile.cpp | 15 +- mozilla/layout/html/forms/src/nsInputFile.h | 4 +- mozilla/layout/html/style/src/nsCSSLayout.cpp | 4 +- mozilla/layout/html/tests/Makefile | 5 +- mozilla/layout/html/tests/TestInlineFrame.cpp | 6 +- mozilla/layout/html/tests/makefile.win | 14 +- mozilla/layout/makefile.win | 2 +- mozilla/layout/style/ua.css | 2 +- 65 files changed, 1191 insertions(+), 20359 deletions(-) delete mode 100644 mozilla/layout/generic/nsBlockFrame.cpp delete mode 100644 mozilla/layout/generic/nsBlockFrame.h delete mode 100644 mozilla/layout/generic/nsBlockReflowState.cpp delete mode 100644 mozilla/layout/generic/nsBlockReflowState.h delete mode 100644 mozilla/layout/generic/nsInlineFrame.cpp delete mode 100644 mozilla/layout/generic/nsLineLayout.cpp delete mode 100644 mozilla/layout/generic/nsLineLayout.h delete mode 100644 mozilla/layout/html/base/src/deadnsInlineFrame.h delete mode 100644 mozilla/layout/html/base/src/nsBlockFrame.cpp delete mode 100644 mozilla/layout/html/base/src/nsBlockFrame.h delete mode 100644 mozilla/layout/html/base/src/nsBlockReflowState.cpp delete mode 100644 mozilla/layout/html/base/src/nsBlockReflowState.h delete mode 100644 mozilla/layout/html/base/src/nsInlineFrame.cpp delete mode 100644 mozilla/layout/html/base/src/nsLineLayout.cpp delete mode 100644 mozilla/layout/html/base/src/nsLineLayout.h diff --git a/mozilla/content/html/style/src/nsCSSLayout.cpp b/mozilla/content/html/style/src/nsCSSLayout.cpp index be0fcccdc1a..42755c0a074 100644 --- a/mozilla/content/html/style/src/nsCSSLayout.cpp +++ b/mozilla/content/html/style/src/nsCSSLayout.cpp @@ -24,7 +24,6 @@ #include "nsIPresContext.h" #include "nsRect.h" #include "nsIPtr.h" -#include "nsBlockFrame.h" #include "nsHTMLIIDs.h" NS_DEF_PTR(nsIStyleContext); @@ -309,6 +308,7 @@ GetStyleDimension(nsIPresContext* aPresContext, rv = PR_TRUE; break; } + aResult = 0; rs = rs->parentReflowState; } } @@ -338,10 +338,12 @@ nsCSSLayout::GetStyleSize(nsIPresContext* aPresContext, if (NS_OK == result) { if (GetStyleDimension(aPresContext, aReflowState, pos, pos->mWidth, aStyleSize.width)) { +NS_ASSERTION(aStyleSize.width < 100000, "bad % result"); rv |= NS_SIZE_HAS_WIDTH; } if (GetStyleDimension(aPresContext, aReflowState, pos, pos->mHeight, aStyleSize.height)) { +NS_ASSERTION(aStyleSize.height < 100000, "bad % result"); rv |= NS_SIZE_HAS_HEIGHT; } } diff --git a/mozilla/layout/Makefile b/mozilla/layout/Makefile index f85dc453da3..77f2a7a3fa0 100644 --- a/mozilla/layout/Makefile +++ b/mozilla/layout/Makefile @@ -17,7 +17,7 @@ DEPTH = .. -DIRS = base html events build +DIRS = base css html events build include $(DEPTH)/config/config.mk diff --git a/mozilla/layout/base/src/nsContainerFrame.cpp b/mozilla/layout/base/src/nsContainerFrame.cpp index c96d018c776..440297ed1d3 100644 --- a/mozilla/layout/base/src/nsContainerFrame.cpp +++ b/mozilla/layout/base/src/nsContainerFrame.cpp @@ -118,7 +118,8 @@ NS_METHOD nsContainerFrame::DidReflow(nsIPresContext& aPresContext, nsDidReflowStatus aStatus) { - NS_FRAME_TRACE_MSG(("enter nsContainerFrame::DidReflow: status=%d", + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("enter nsContainerFrame::DidReflow: status=%d", aStatus)); if (NS_FRAME_REFLOW_FINISHED == aStatus) { nsFrameState state; @@ -492,7 +493,6 @@ nsReflowStatus nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, // the right parent to do the removal (it's possible that the // parent is not this because we are executing pullup code) nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); ((nsContainerFrame*)parent)->DeleteChildsNextInFlow(aKidFrame); } @@ -510,7 +510,8 @@ nsReflowStatus nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, * @param aChild child this child's next-in-flow * @return PR_TRUE if successful and PR_FALSE otherwise */ -PRBool nsContainerFrame::DeleteChildsNextInFlow(nsIFrame* aChild) +PRBool +nsContainerFrame::DeleteChildsNextInFlow(nsIFrame* aChild) { NS_PRECONDITION(IsChild(aChild), "bad geometric parent"); @@ -527,7 +528,7 @@ PRBool nsContainerFrame::DeleteChildsNextInFlow(nsIFrame* aChild) nextInFlow->GetNextInFlow(nextNextInFlow); if (nsnull != nextNextInFlow) { - ((nsContainerFrame*)parent)->DeleteChildsNextInFlow(nextInFlow); + parent->DeleteChildsNextInFlow(nextInFlow); } #ifdef NS_DEBUG @@ -594,17 +595,11 @@ PRBool nsContainerFrame::DeleteChildsNextInFlow(nsIFrame* aChild) WillDeleteNextInFlowFrame(nextInFlow); nextInFlow->DeleteFrame(); parent->mChildCount--; -#ifdef NS_DEBUG -#if XXX_new_block_doesn_t_work_with_this_check - if (0 != parent->mChildCount) { - parent->CheckContentOffsets(); - } -#endif +#ifdef NS_DEBUG aChild->GetNextInFlow(nextInFlow); NS_POSTCONDITION(nsnull == nextInFlow, "non null next-in-flow"); #endif - return PR_TRUE; } @@ -766,74 +761,6 @@ void nsContainerFrame::PushChildren(nsIFrame* aFromChild, } } -// Note: mLastContentIsComplete is not set correctly by this routine -// (we don't always know the correct value at this time) -nsIFrame* nsContainerFrame::PullUpOneChild(nsContainerFrame* aNextInFlow, - nsIFrame* aLastChild) -{ - NS_PRECONDITION(nsnull != aNextInFlow, "null ptr"); -#ifdef NS_DEBUG - if (nsnull != aLastChild) { - NS_PRECONDITION(IsLastChild(aLastChild), "bad last child"); - } -#endif - - // Get first available frame from the next-in-flow - NS_ASSERTION(nsnull == aNextInFlow->mOverflowList, "bad next in flow"); - nsIFrame* kidFrame = aNextInFlow->mFirstChild; - if (nsnull == kidFrame) { - return nsnull; - } - -#ifdef NOISY - ListTag(stdout); - printf(": pulled "); - kidFrame->ListTag(stdout); - printf("\n"); -#endif - - // Take the frame away from the next-in-flow. Update it's first - // content offset and propagate upward the offset if the - // next-in-flow is a pseudo-frame. - kidFrame->GetNextSibling(aNextInFlow->mFirstChild); - aNextInFlow->mChildCount--; - if (nsnull != aNextInFlow->mFirstChild) { - aNextInFlow->SetFirstContentOffset(aNextInFlow->mFirstChild); - if (aNextInFlow->IsPseudoFrame()) { - aNextInFlow->PropagateContentOffsets(); - } - } else { -#ifdef NOISY - ListTag(stdout); - printf(": drained next-in-flow %p\n", aNextInFlow); -#endif - } - - // Now give the frame to this container - kidFrame->SetGeometricParent(this); - - nsIFrame* contentParent; - - kidFrame->GetContentParent(contentParent); - if (aNextInFlow == contentParent) { - kidFrame->SetContentParent(this); - } - if (nsnull == aLastChild) { - mFirstChild = kidFrame; - SetFirstContentOffset(kidFrame); - // If we are a pseudo-frame propagate our first offset upward - if (IsPseudoFrame()) { - PropagateContentOffsets(); - } - } else { - aLastChild->SetNextSibling(kidFrame); - } - kidFrame->SetNextSibling(nsnull); - mChildCount++; - - return kidFrame; -} - /** * Moves any frames on the overflwo lists (the prev-in-flow's overflow list and * the receiver's overflow list) to the child list. @@ -1020,9 +947,6 @@ NS_METHOD nsContainerFrame::List(FILE* out, PRInt32 aIndent) const // Output the children if (mChildCount > 0) { - if (!mLastContentIsComplete) { - fputs(", !complete", out); - } if (0 != mState) { fprintf(out, " [state=%08x]", mState); } diff --git a/mozilla/layout/base/src/nsContainerFrame.h b/mozilla/layout/base/src/nsContainerFrame.h index 18eadcfae0e..0c13ee7937a 100644 --- a/mozilla/layout/base/src/nsContainerFrame.h +++ b/mozilla/layout/base/src/nsContainerFrame.h @@ -190,7 +190,7 @@ public: * * It's a precondition that this frame must be a pseudo-frame. */ - void PropagateContentOffsets(); + virtual void PropagateContentOffsets(); protected: // Constructor. Takes as arguments the content object, the index in parent, @@ -237,22 +237,16 @@ protected: */ PRBool MoveOverflowToChildList(); - /** - * Remove and delete aChild's next-in-flow(s). Updates the sibling and flow - * pointers - * - * Updates the child count and content offsets of all containers that are - * affected - * - * @param aChild child this child's next-in-flow - * @return PR_TRUE if successful and PR_FALSE otherwise - */ - PRBool DeleteChildsNextInFlow(nsIFrame* aChild); - - static PRBool DeleteNextInFlowsFor(nsContainerFrame* aParent, nsIFrame* aKid) - { - return aParent->DeleteChildsNextInFlow(aKid); - } + /** + * Remove and delete aChild's next-in-flow(s). Updates the sibling and flow + * pointers. + * + * Updates the child count and content offsets of all containers that are + * affected. + * + * @param aChild child this child's next-in-flow + */ + PRBool DeleteChildsNextInFlow(nsIFrame* aChild); /** * Push aFromChild and its next siblings to the next-in-flow. Change the @@ -274,27 +268,6 @@ protected: void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling, PRBool aNextInFlowsLastChildIsComplete); - /** - * Attempt to pull one child from the next-in-flow, if any. This - * does everything necessary for the receiving frame and the - * next-in-flow frame to ensure that the content offsets and - * mLastContentIsComplete flags are correct, and it makes sure that - * the parent offsets if this frame or the next is a pseudo-frame - * are correct. If there are no children to pull from the next - * in flow, nsnull is returned. - * - * If the caller decides that it doesn't want the child from the - * next in flow, it can call PushChildren to push it back. - * - * @param aNextInFlow the next-in-flow frame to attempt to pull a child - * from - * @param aLastChild the current last child for this frame. If a child - * is pullable then the child will become aLastChild's next - * sibling - */ - nsIFrame* PullUpOneChild(nsContainerFrame* aNextInFlow, - nsIFrame* aLastChild); - /** * Called after pulling-up children from the next-in-flow. Adjusts the first * content offset of all the empty next-in-flows diff --git a/mozilla/layout/base/src/nsFrame.cpp b/mozilla/layout/base/src/nsFrame.cpp index 547bfe39e0b..18a68afc6eb 100644 --- a/mozilla/layout/base/src/nsFrame.cpp +++ b/mozilla/layout/base/src/nsFrame.cpp @@ -1026,7 +1026,8 @@ nsFrame::SetFrameState(nsFrameState aNewState) NS_METHOD nsFrame::WillReflow(nsIPresContext& aPresContext) { - NS_FRAME_TRACE_MSG(("WillReflow: oldState=%x", mState)); + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("WillReflow: oldState=%x", mState)); mState |= NS_FRAME_IN_REFLOW; return NS_OK; } @@ -1035,7 +1036,8 @@ NS_METHOD nsFrame::DidReflow(nsIPresContext& aPresContext, nsDidReflowStatus aStatus) { - NS_FRAME_TRACE_MSG(("nsFrame::DidReflow: aStatus=%d", aStatus)); + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("nsFrame::DidReflow: aStatus=%d", aStatus)); if (NS_FRAME_REFLOW_FINISHED == aStatus) { mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW); diff --git a/mozilla/layout/base/src/nsFrame.h b/mozilla/layout/base/src/nsFrame.h index c0c4aacd875..bfbd34f63ba 100644 --- a/mozilla/layout/base/src/nsFrame.h +++ b/mozilla/layout/base/src/nsFrame.h @@ -34,6 +34,7 @@ #define NS_FRAME_TRACE_CALLS 0x1 #define NS_FRAME_TRACE_PUSH_PULL 0x2 #define NS_FRAME_TRACE_CHILD_REFLOW 0x4 +#define NS_FRAME_TRACE_NEW_FRAMES 0x8 #define NS_FRAME_LOG_TEST(_lm,_bit) (PRIntn((_lm)->level) & (_bit)) @@ -48,17 +49,36 @@ #define NS_FRAME_LOG(_bit,_args) #endif +// XXX Need to rework this so that logging is free when it's off #ifdef NS_DEBUG #define NS_FRAME_TRACE_IN(_method) Trace(_method, PR_TRUE) + #define NS_FRAME_TRACE_OUT(_method) Trace(_method, PR_FALSE) -#define NS_FRAME_TRACE_MSG(_args) TraceMsg _args + +// XXX remove me +#define NS_FRAME_TRACE_MSG(_bit,_args) \ + PR_BEGIN_MACRO \ + if (NS_FRAME_LOG_TEST(nsIFrame::GetLogModuleInfo(),_bit)) { \ + TraceMsg _args; \ + } \ + PR_END_MACRO + +#define NS_FRAME_TRACE(_bit,_args) \ + PR_BEGIN_MACRO \ + if (NS_FRAME_LOG_TEST(nsIFrame::GetLogModuleInfo(),_bit)) { \ + TraceMsg _args; \ + } \ + PR_END_MACRO + #define NS_FRAME_TRACE_REFLOW_IN(_method) Trace(_method, PR_TRUE) + #define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) \ Trace(_method, PR_FALSE, _status) + #else #define NS_FRAME_TRACE_IN(_method) #define NS_FRAME_TRACE_OUT(_method) -#define NS_FRAME_TRACE_MSG(_args) +#define NS_FRAME_TRACE_MSG(_bits,_args) #define NS_FRAME_TRACE_REFLOW_IN(_method) #define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) #endif diff --git a/mozilla/layout/base/src/nsSplittableFrame.cpp b/mozilla/layout/base/src/nsSplittableFrame.cpp index eb6657c6f98..22e79414a06 100644 --- a/mozilla/layout/base/src/nsSplittableFrame.cpp +++ b/mozilla/layout/base/src/nsSplittableFrame.cpp @@ -87,6 +87,8 @@ nsSplittableFrame::CreateContinuingFrame(nsIPresContext* aPresContext, // Append the continuing frame to the flow aContinuingFrame->AppendToFlow(this); + // XXX remove this! + // Resolve style for the continuing frame and set its style context. nsIStyleContext* styleContext = aPresContext->ResolveStyleContextFor(mContent, aParent); diff --git a/mozilla/layout/build/makefile.win b/mozilla/layout/build/makefile.win index 5db17e6f42d..653788fa3ef 100644 --- a/mozilla/layout/build/makefile.win +++ b/mozilla/layout/build/makefile.win @@ -35,6 +35,7 @@ DLL=.\$(OBJDIR)\$(DLLNAME).dll MISCDEP = \ $(DIST)\lib\raptorlayout_s.lib \ $(DIST)\lib\raptorhtmlbase_s.lib \ + $(DIST)\lib\nglcsslay_s.lib \ $(DIST)\lib\raptorhtmldoc_s.lib \ $(DIST)\lib\raptorhtmlforms_s.lib \ $(DIST)\lib\raptorhtmlstyle_s.lib \ @@ -59,6 +60,7 @@ LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I..\..\style\src LLIBS= \ $(DIST)\lib\raptorlayout_s.lib \ $(DIST)\lib\raptorhtmlbase_s.lib \ + $(DIST)\lib\nglcsslay_s.lib \ $(DIST)\lib\raptorhtmldoc_s.lib \ $(DIST)\lib\raptorhtmlforms_s.lib \ $(DIST)\lib\raptorhtmlstyle_s.lib \ diff --git a/mozilla/layout/css/layout/src/nsCSSBlockFrame.cpp b/mozilla/layout/css/layout/src/nsCSSBlockFrame.cpp index 24534a533c3..aa1bf454934 100644 --- a/mozilla/layout/css/layout/src/nsCSSBlockFrame.cpp +++ b/mozilla/layout/css/layout/src/nsCSSBlockFrame.cpp @@ -93,7 +93,7 @@ struct LineData; #define DTPF 1 // XXX temporary until PropagateContentOffsets can be written genericly -#define nsCSSBlockFrameSuper nsContainerFrame +#define nsCSSBlockFrameSuper nsCSSContainerFrame class nsCSSBlockFrame : public nsCSSBlockFrameSuper, public nsIRunaround, @@ -113,7 +113,6 @@ public: NS_IMETHOD NextChild(const nsIFrame* aChild, nsIFrame*& aNextChild) const; NS_IMETHOD PrevChild(const nsIFrame* aChild, nsIFrame*& aPrevChild) const; NS_IMETHOD LastChild(nsIFrame*& aLastChild) const; - NS_IMETHOD DeleteChildsNextInFlow(nsIFrame* aNextInFlow); NS_IMETHOD IsSplittable(nsSplittableType& aIsSplittable) const; NS_IMETHOD CreateContinuingFrame(nsIPresContext* aPresContext, nsIFrame* aParent, @@ -127,6 +126,13 @@ public: nsIContent* aContainer); NS_IMETHOD DidReflow(nsIPresContext& aPresContext, nsDidReflowStatus aStatus); + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + NS_IMETHOD GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame, + PRInt32& aCursor); NS_IMETHOD List(FILE* out, PRInt32 aIndent) const; NS_IMETHOD ListTag(FILE* out) const; NS_IMETHOD VerifyTree() const; @@ -156,6 +162,7 @@ protected: PRBool GetLastContentIsComplete() const; #endif + virtual PRBool DeleteNextInFlowsFor(nsIFrame* aNextInFlow); nsresult DrainOverflowLines(); @@ -165,8 +172,6 @@ protected: //XXX void PropagateContentOffsets(); - //XXX virtual void WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow); - PRIntn GetSkipSides() const; PRBool IsPseudoFrame() const; @@ -322,6 +327,16 @@ LineData::~LineData() } } +static void +ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters) +{ + PRInt32 i, n = aFloaters->Count(); + for (i = 0; i < n; i++) { + nsIFrame* frame = (nsIFrame*) aFloaters->ElementAt(i); + frame->List(out, aIndent); + } +} + void LineData::List(FILE* out, PRInt32 aIndent) const { @@ -341,12 +356,8 @@ LineData::List(FILE* out, PRInt32 aIndent) const for (i = aIndent; --i >= 0; ) fputs(" ", out); if (nsnull != mFloaters) { - PRInt32 j, n = mFloaters->Count(); - fprintf(out, "> #floaters=%d<\n", n); - for (j = 0; j < n; j++) { - nsIFrame* frame = (nsIFrame*) mFloaters->ElementAt(j); - frame->List(out, aIndent + 1); - } + fputs("> bcl-floaters=<\n", out); + ListFloaters(out, aIndent + 1, mFloaters); for (i = aIndent; --i >= 0; ) fputs(" ", out); } fputs(">\n", out); @@ -445,10 +456,22 @@ VerifyChildCount(LineData* aLines, PRBool aEmptyOK = PR_FALSE) static void DeleteLineList(LineData* aLine) { - while (nsnull != aLine) { - LineData* next = aLine->mNext; - delete aLine; - aLine = next; + if (nsnull != aLine) { + // Delete our child frames before doing anything else. In particular + // we do all of this before our base class releases it's hold on the + // view. + for (nsIFrame* child = aLine->mFirstChild; child; ) { + nsIFrame* nextChild; + child->GetNextSibling(nextChild); + child->DeleteFrame(); + child = nextChild; + } + + while (nsnull != aLine) { + LineData* next = aLine->mNext; + delete aLine; + aLine = next; + } } } @@ -532,7 +555,7 @@ nsCSSBlockReflowState::nsCSSBlockReflowState(nsIPresContext* aPresContext, nsCSSBlockFrame* aBlock, nsIStyleContext* aBlockSC, const nsReflowState& aReflowState, - nsSize* aMaxElementSize) + PRBool aComputeMaxElementSize) : nsReflowState(aBlock, *aReflowState.parentReflowState, aReflowState.maxSize), mLineLayout(aPresContext, aSpaceManager), @@ -553,12 +576,10 @@ nsCSSBlockReflowState::nsCSSBlockReflowState(nsIPresContext* aPresContext, mY = 0; mUnconstrainedWidth = aReflowState.maxSize.width == NS_UNCONSTRAINEDSIZE; mUnconstrainedHeight = aReflowState.maxSize.height == NS_UNCONSTRAINEDSIZE; - mMaxElementSize = aMaxElementSize; - if (nsnull != aMaxElementSize) { - // XXX CAN'T pass our's to an inline child frame because it will - // do the same thing... - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; + mComputeMaxElementSize = aComputeMaxElementSize; + if (mComputeMaxElementSize) { + mMaxElementSize.width = 0; + mMaxElementSize.height = 0; } // Set mNoWrap flag @@ -578,9 +599,18 @@ nsCSSBlockReflowState::nsCSSBlockReflowState(nsIPresContext* aPresContext, aBlockSC->GetStyleData(eStyleStruct_Display); mDirection = styleDisplay->mDirection; + if (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) { + const nsStyleList* sl = (const nsStyleList*) + aBlockSC->GetStyleData(eStyleStruct_List); + if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == sl->mListStylePosition) { + mLineLayout.mListPositionOutside = PR_TRUE; + } + } + // Apply border and padding adjustments for regular frames only nsRect blockRect; mBlock->GetRect(blockRect); + mStyleSizeFlags = 0; if (!mBlockIsPseudo) { const nsStyleSpacing* blockSpacing = (const nsStyleSpacing*) aBlockSC->GetStyleData(eStyleStruct_Spacing); @@ -665,9 +695,17 @@ nsCSSBlockReflowState::nsCSSBlockReflowState(nsIPresContext* aPresContext, nsCSSBlockReflowState::~nsCSSBlockReflowState() { - // XXX release free list + LineData* line = mFreeList; + while (nsnull != line) { + NS_ASSERTION((0 == line->mChildCount) && (nsnull == line->mFirstChild), + "bad free line"); + LineData* next = line->mNext; + delete line; + line = next; + } } +// XXX I think the handling of mBorderPadding.left is weird here. void nsCSSBlockReflowState::GetAvailableSpace() { @@ -675,15 +713,18 @@ nsCSSBlockReflowState::GetAvailableSpace() nsISpaceManager* sm = mSpaceManager; - // Fill in band data for the specific Y coordinate - sm->Translate(mBorderPadding.left, mY); - sm->GetBandData(0, mInnerSize, mCurrentBand); - sm->Translate(-mBorderPadding.left, -mY); + // Fill in band data for the specific Y coordinate. Note: We don't + // translate by Y so that the band will be absolute (at least in y); + // this makes the implementation of ClearFloaters simpler. + sm->Translate(mBorderPadding.left, 0); + sm->GetBandData(mY, mInnerSize, mCurrentBand); + sm->Translate(-mBorderPadding.left, 0); // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters + // between any left and right floaters. The availSpace is translated + // after it's computed to be fully absolute. mCurrentBand.ComputeAvailSpaceRect(); - mCurrentBand.availSpace.MoveBy(mBorderPadding.left, mY); + mCurrentBand.availSpace.MoveBy(mBorderPadding.left, 0); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("nsCSSBlockReflowState::GetAvailableSpace: band={%d,%d,%d,%d}", @@ -731,12 +772,11 @@ nsCSSBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) if (NULL == aInstancePtr) { return NS_ERROR_NULL_POINTER; } -#if 0 + // XXX temporary if (aIID.Equals(kBlockFrameCID)) { *aInstancePtr = (void*) (this); return NS_OK; } -#endif if (aIID.Equals(kIRunaroundIID)) { *aInstancePtr = (void*) ((nsIRunaround*) this); return NS_OK; @@ -839,16 +879,23 @@ nsCSSBlockFrame::List(FILE* out, PRInt32 aIndent) const fprintf(out, "next-in-flow=%p ", mNextInFlow); } - // Output the rect + // Output the rect and state out << mRect; + if (0 != mState) { + fprintf(out, " [state=%08x]", mState); + } + + // Dump run-in floaters + if (nsnull != mRunInFloaters) { + fputs(" run-in-floaters=<\n", out); + ListFloaters(out, aIndent + 1, mRunInFloaters); + for (i = aIndent; --i >= 0; ) fputs(" ", out); + fputs(">", out); + } // Output the children, one line at a time if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } fputs("<\n", out); - aIndent++; LineData* line = mLines; while (nsnull != line) { @@ -856,13 +903,10 @@ nsCSSBlockFrame::List(FILE* out, PRInt32 aIndent) const line = line->mNext; } aIndent--; - for (i = aIndent; --i >= 0; ) fputs(" ", out); fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } + } + else { fputs("<>\n", out); } @@ -1053,7 +1097,8 @@ nsCSSBlockFrame::Reflow(nsIPresContext* aPresContext, // more extensive version. nsCSSBlockReflowState state(aPresContext, aSpaceManager, this, mStyleContext, - aReflowState, aMetrics.maxElementSize); + aReflowState, + PRBool(nsnull != aMetrics.maxElementSize)); nsresult rv = NS_OK; if (eReflowReason_Initial == state.reason) { @@ -1264,6 +1309,10 @@ nsCSSBlockFrame::ComputeFinalSize(nsCSSBlockReflowState& aState, aMetrics.height = aDesiredRect.height; aMetrics.ascent = aMetrics.height; aMetrics.descent = 0; + if (aState.mComputeMaxElementSize) { + *aMetrics.maxElementSize = aState.mMaxElementSize; + } + NS_ASSERTION(aDesiredRect.width < 1000000, "whoops"); } // XXX move this somewhere else!!! @@ -1492,6 +1541,10 @@ nsCSSBlockFrame::ResizeReflow(nsCSSBlockReflowState& aState) nsresult nsCSSBlockFrame::ReflowLinesAt(nsCSSBlockReflowState& aState, LineData* aLine) { + if (nsnull != mRunInFloaters) { + aState.PlaceBelowCurrentLineFloaters(mRunInFloaters); + } + // Reflow the lines that are already ours while (nsnull != aLine) { nsInlineReflowStatus rs; @@ -1501,6 +1554,7 @@ nsCSSBlockFrame::ReflowLinesAt(nsCSSBlockReflowState& aState, LineData* aLine) } return NS_FRAME_NOT_COMPLETE; } + aState.mLineLayout.NextLine(); aState.mPrevLine = aLine; aLine = aLine->mNext; } @@ -1573,6 +1627,7 @@ nsCSSBlockFrame::ReflowLinesAt(nsCSSBlockReflowState& aState, LineData* aLine) } return NS_FRAME_NOT_COMPLETE; } + aState.mLineLayout.NextLine(); aState.mPrevLine = aLine; aLine = aLine->mNext; } @@ -1733,16 +1788,22 @@ nsCSSBlockFrame::ReflowBlockFrame(nsCSSBlockReflowState& aState, if (NS_FRAME_FIRST_REFLOW & state) { reason = eReflowReason_Initial; } -#if XXX_fix_me - else if (nsnull != aState.reflowCommand) { - reason = eReflowReason_Incremental; + else + if (nsnull != aState.reflowCommand) { + nsIFrame* target; + aState.reflowCommand->GetTarget(target); + if (this != target) { + reason = eReflowReason_Incremental; + } } -#endif // Reflow the block frame. Use the run-around API if possible; // otherwise treat it as a rectangular lump and place it. nsresult rv; - nsReflowMetrics metrics(aState.mMaxElementSize);/* XXX mMaxElementSize*/ + nsSize kidMaxElementSize; + nsReflowMetrics metrics(aState.mComputeMaxElementSize + ? &kidMaxElementSize + : nsnull); nsReflowStatus reflowStatus; nsIRunaround* runAround; if ((nsnull != aState.mSpaceManager) && @@ -1752,8 +1813,10 @@ nsCSSBlockFrame::ReflowBlockFrame(nsCSSBlockReflowState& aState, nsReflowState reflowState(aFrame, aState, availSize); reflowState.reason = reason; nsRect r; + aState.mSpaceManager->Translate(x, y); rv = runAround->Reflow(aState.mPresContext, aState.mSpaceManager, metrics, reflowState, r, reflowStatus); + aState.mSpaceManager->Translate(-x, -y); metrics.width = r.width; metrics.height = r.height; metrics.ascent = r.height; @@ -1779,7 +1842,7 @@ nsCSSBlockFrame::ReflowBlockFrame(nsCSSBlockReflowState& aState, // parent is not this because we are executing pullup code) nsIFrame* parent; aFrame->GetGeometricParent(parent); - parent->DeleteChildsNextInFlow(aFrame); + ((nsCSSBlockFrame*)parent)->DeleteNextInFlowsFor(aFrame); } aLine->SetLastContentIsComplete(); aReflowResult = NS_INLINE_REFLOW_COMPLETE; @@ -1801,6 +1864,16 @@ nsCSSBlockFrame::ReflowBlockFrame(nsCSSBlockReflowState& aState, return PR_FALSE; } + // Update max-element-size + if (aState.mComputeMaxElementSize) { + if (kidMaxElementSize.width > aState.mMaxElementSize.width) { + aState.mMaxElementSize.width = kidMaxElementSize.width; + } + if (kidMaxElementSize.height > aState.mMaxElementSize.height) { + aState.mMaxElementSize.height = kidMaxElementSize.height; + } + } + // Save away bounds before other adjustments aLine->mBounds.x = x; aLine->mBounds.y = y; @@ -1867,8 +1940,9 @@ nsCSSBlockFrame::ReflowInlineFrame(nsCSSBlockReflowState& aState, nsInlineReflowStatus& aReflowResult) { if (!aState.mInlineLayoutPrepared) { + aState.mLineLayout.Prepare(aState.mX); aState.mInlineLayout.Prepare(aState.mUnconstrainedWidth, aState.mNoWrap, - aState.mMaxElementSize); + aState.mComputeMaxElementSize); aState.mInlineLayout.SetReflowSpace(aState.mCurrentBand.availSpace.x, aState.mY, aState.mCurrentBand.availSpace.width, @@ -2075,6 +2149,17 @@ nsCSSBlockFrame::PlaceLine(nsCSSBlockReflowState& aState, return PR_FALSE; } + // Update max-element-size + if (aState.mComputeMaxElementSize) { + nsSize& lineMaxElementSize = aState.mInlineLayout.mMaxElementSize; + if (lineMaxElementSize.width > aState.mMaxElementSize.width) { + aState.mMaxElementSize.width = lineMaxElementSize.width; + } + if (lineMaxElementSize.height > aState.mMaxElementSize.height) { + aState.mMaxElementSize.height = lineMaxElementSize.height; + } + } + nscoord xmost = aLine->mBounds.XMost(); if (xmost > aState.mKidXMost) { aState.mKidXMost = xmost; @@ -2083,7 +2168,7 @@ nsCSSBlockFrame::PlaceLine(nsCSSBlockReflowState& aState, // Based on the last child we reflowed reflow status, we may need to // clear past any floaters. - PRBool updateReflowSpace = PR_FALSE; +//XXX PRBool updateReflowSpace = PR_FALSE; if (NS_INLINE_REFLOW_BREAK_AFTER == (aReflowStatus & NS_INLINE_REFLOW_REFLOW_MASK)) { // Apply break to the line @@ -2094,8 +2179,11 @@ nsCSSBlockFrame::PlaceLine(nsCSSBlockReflowState& aState, case NS_STYLE_CLEAR_LEFT: case NS_STYLE_CLEAR_RIGHT: case NS_STYLE_CLEAR_LEFT_AND_RIGHT: + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, + ("nsCSSBlockFrame::PlaceLine: clearing floaters=%d", + breakType)); aState.ClearFloaters(breakType); - updateReflowSpace = PR_TRUE; +//XXX updateReflowSpace = PR_TRUE; break; } // XXX page breaks, etc, need to be passed upwards too! @@ -2125,15 +2213,17 @@ nsCSSBlockFrame::PlaceLine(nsCSSBlockReflowState& aState, // The current y coordinate is now past our available space // rectangle. Get a new band of space. aState.GetAvailableSpace(); - updateReflowSpace = PR_TRUE; +//XXX updateReflowSpace = PR_TRUE; } +#if XXX if (updateReflowSpace) { aState.mInlineLayout.SetReflowSpace(aState.mCurrentBand.availSpace.x, aState.mY, aState.mCurrentBand.availSpace.width, aState.mCurrentBand.availSpace.height); } +#endif return PR_TRUE; } @@ -2280,8 +2370,8 @@ nsCSSBlockFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } -NS_IMETHODIMP -nsCSSBlockFrame::DeleteChildsNextInFlow(nsIFrame* aChild) +PRBool +nsCSSBlockFrame::DeleteNextInFlowsFor(nsIFrame* aChild) { NS_PRECONDITION(IsChild(aChild), "bad geometric parent"); @@ -2297,7 +2387,7 @@ nsCSSBlockFrame::DeleteChildsNextInFlow(nsIFrame* aChild) nsIFrame* nextNextInFlow; nextInFlow->GetNextInFlow(nextNextInFlow); if (nsnull != nextNextInFlow) { - parent->DeleteChildsNextInFlow(nextInFlow); + parent->DeleteNextInFlowsFor(nextInFlow); } #ifdef NS_DEBUG @@ -2351,7 +2441,7 @@ nsCSSBlockFrame::DeleteChildsNextInFlow(nsIFrame* aChild) aChild->GetNextInFlow(nextInFlow); NS_POSTCONDITION(nsnull == nextInFlow, "non null next-in-flow"); #endif - return NS_OK; + return PR_TRUE; } PRBool @@ -2605,7 +2695,7 @@ nsCSSBlockReflowState::PlaceBelowCurrentLineFloaters(nsVoidArray* aFloaterList) nsISpaceManager* sm = mSpaceManager; - // XXX Factor this code with PlaceFloater()... + // XXX Factor this code with PlaceCurrentLineFloater()... nsRect region; PRInt32 numFloaters = aFloaterList->Count(); for (PRInt32 i = 0; i < numFloaters; i++) { @@ -2677,21 +2767,33 @@ nsCSSBlockReflowState::ClearFloaters(PRUint8 aBreakType) break; } - // Find the Y coordinate to clear to + // Find the Y coordinate to clear to. Note that the band trapezoid + // coordinates are relative to the last translation. Since we + // never translate by Y before getting a band, we can use absolute + // comparisons against mY. + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: mY=%d trapCount=%d", + mY, mCurrentBand.count)); nscoord clearYMost = mY; nsRect tmp; PRInt32 i; for (i = 0; i < mCurrentBand.count; i++) { const nsStyleDisplay* display; nsBandTrapezoid* trapezoid = &mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: trap=%d state=%d", + i, trapezoid->state)); + if (nsBandTrapezoid::Available != trapezoid->state) { if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { PRInt32 fn, numFrames = trapezoid->frames->Count(); NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); + nsIFrame* frame = (nsIFrame*) trapezoid->frames->ElementAt(fn); + frame->GetStyleData(eStyleStruct_Display, + (const nsStyleStruct*&)display); + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: frame[%d]=%p floats=%d", + fn, frame, display->mFloats)); switch (display->mFloats) { case NS_STYLE_FLOAT_LEFT: if ((NS_STYLE_CLEAR_LEFT == aBreakType) || @@ -2700,6 +2802,9 @@ nsCSSBlockReflowState::ClearFloaters(PRUint8 aBreakType) nscoord ym = tmp.YMost(); if (ym > clearYMost) { clearYMost = ym; + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: left clearYMost=%d", + clearYMost)); } } break; @@ -2710,6 +2815,9 @@ nsCSSBlockReflowState::ClearFloaters(PRUint8 aBreakType) nscoord ym = tmp.YMost(); if (ym > clearYMost) { clearYMost = ym; + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: right clearYMost=%d", + clearYMost)); } } break; @@ -2719,14 +2827,23 @@ nsCSSBlockReflowState::ClearFloaters(PRUint8 aBreakType) else { trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: frame=%p floats=%d", + trapezoid->frame, display->mFloats)); switch (display->mFloats) { case NS_STYLE_FLOAT_LEFT: if ((NS_STYLE_CLEAR_LEFT == aBreakType) || (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { trapezoid->GetRect(tmp); nscoord ym = tmp.YMost(); +NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: left? ym=%d clearYMost=%d", + ym, clearYMost)); if (ym > clearYMost) { clearYMost = ym; + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: left clearYMost=%d", + clearYMost)); } } break; @@ -2737,6 +2854,9 @@ nsCSSBlockReflowState::ClearFloaters(PRUint8 aBreakType) nscoord ym = tmp.YMost(); if (ym > clearYMost) { clearYMost = ym; + NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, + ("nsCSSBlockReflowState::ClearFloaters: right clearYMost=%d", + clearYMost)); } } break; @@ -2884,6 +3004,54 @@ nsCSSBlockFrame::PaintChildren(nsIPresContext& aPresContext, } } +// XXX move into nsFrame +NS_IMETHODIMP +nsCSSBlockFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + aEventStatus = nsEventStatus_eIgnore; + + nsIFrame* kid = (nsnull == mLines) ? nsnull : mLines->mFirstChild; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + if (kidRect.Contains(aEvent->point)) { + aEvent->point.MoveBy(-kidRect.x, -kidRect.y); + kid->HandleEvent(aPresContext, aEvent, aEventStatus); + aEvent->point.MoveBy(kidRect.x, kidRect.y); + break; + } + kid->GetNextSibling(kid); + } + + return NS_OK; +} + +// XXX move into nsFrame +NS_IMETHODIMP +nsCSSBlockFrame::GetCursorAt(nsIPresContext& aPresContext, + const nsPoint& aPoint, + nsIFrame** aFrame, + PRInt32& aCursor) +{ + aCursor = NS_STYLE_CURSOR_INHERIT; + + nsIFrame* kid = (nsnull == mLines) ? nsnull : mLines->mFirstChild; + nsPoint tmp; + while (nsnull != kid) { + nsRect kidRect; + kid->GetRect(kidRect); + if (kidRect.Contains(aPoint)) { + tmp.MoveTo(aPoint.x - kidRect.x, aPoint.y - kidRect.y); + kid->GetCursorAt(aPresContext, tmp, aFrame, aCursor); + break; + } + kid->GetNextSibling(kid); + } + return NS_OK; +} + ////////////////////////////////////////////////////////////////////// // Debugging diff --git a/mozilla/layout/css/layout/src/nsCSSBlockFrame.h b/mozilla/layout/css/layout/src/nsCSSBlockFrame.h index 19d4aed1408..136d7e1ddca 100644 --- a/mozilla/layout/css/layout/src/nsCSSBlockFrame.h +++ b/mozilla/layout/css/layout/src/nsCSSBlockFrame.h @@ -19,7 +19,7 @@ #ifndef nsCSSBlockFrame_h___ #define nsCSSBlockFrame_h___ -#include "nsContainerFrame.h" +#include "nsCSSContainerFrame.h" #include "nsCSSLineLayout.h" #include "nsCSSInlineLayout.h" #include "nsVoidArray.h" @@ -29,6 +29,10 @@ class nsCSSBlockFrame; struct nsCSSInlineLayout; struct LineData; +/* 52b33130-0b99-11d2-932e-00805f8add32 */ +#define NS_BLOCK_FRAME_CID \ +{ 0x52b33130, 0x0b99, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}} + // XXX hide this as soon as list bullet code is cleaned up struct nsCSSBlockReflowState : public nsReflowState { @@ -37,7 +41,7 @@ struct nsCSSBlockReflowState : public nsReflowState { nsCSSBlockFrame* aBlock, nsIStyleContext* aBlockSC, const nsReflowState& aReflowState, - nsSize* aMaxElementSize); + PRBool aComputeMaxElementSize); ~nsCSSBlockReflowState(); @@ -67,14 +71,16 @@ struct nsCSSBlockReflowState : public nsReflowState { nscoord mDeltaWidth; nscoord mBottomEdge; // maximum Y - PRPackedBool mUnconstrainedWidth, mUnconstrainedHeight; + PRPackedBool mUnconstrainedWidth; + PRPackedBool mUnconstrainedHeight; PRPackedBool mNoWrap; + PRPackedBool mComputeMaxElementSize; nscoord mX, mY; nscoord mPrevPosBottomMargin; nscoord mPrevNegBottomMargin; nscoord mKidXMost; - nsSize* mMaxElementSize; + nsSize mMaxElementSize; nsCSSLineLayout mLineLayout; diff --git a/mozilla/layout/css/layout/src/nsCSSContainerFrame.h b/mozilla/layout/css/layout/src/nsCSSContainerFrame.h index 8e882139180..d578c4733d4 100644 --- a/mozilla/layout/css/layout/src/nsCSSContainerFrame.h +++ b/mozilla/layout/css/layout/src/nsCSSContainerFrame.h @@ -23,25 +23,12 @@ class nsCSSContainerFrame : public nsHTMLContainerFrame { public: -#if 0 - NS_IMETHOD ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer); -#endif + + virtual PRBool DeleteNextInFlowsFor(nsIFrame* aChild) = 0; protected: nsCSSContainerFrame(nsIContent* aContent, nsIFrame* aParent); ~nsCSSContainerFrame(); - -#if 0 - PRInt32 NextChildOffset() const { - return mLastContentOffset + (mLastContentIsComplete ? 1 : 0); - } - - PRInt32 mFirstContentOffset; - PRInt32 mLastContentOffset; - PRBool mLastContentIsComplete; // XXX move into frame-state -#endif }; #endif /* nsCSSContainerFrame_h___ */ diff --git a/mozilla/layout/css/layout/src/nsCSSInlineFrame.cpp b/mozilla/layout/css/layout/src/nsCSSInlineFrame.cpp index 8c142f0e3d8..906fe532271 100644 --- a/mozilla/layout/css/layout/src/nsCSSInlineFrame.cpp +++ b/mozilla/layout/css/layout/src/nsCSSInlineFrame.cpp @@ -25,6 +25,15 @@ #include "nsHTMLBase.h"// XXX rename to nsCSSBase? // XXX TODO: + +// test: ...
: make sure that it works in pullup case and +// non-pullup case + +// XXX As coded today, the reflow-status is mapped into +// complete/not-complete before returning. If we want to support other +// kinds of breaks we need to return the complete breaking status +// outward properly. + // content appended INCREMENTAL reflow // content inserted INCREMENTAL reflow // content deleted INCREMENTAL reflow @@ -33,7 +42,7 @@ nsCSSInlineReflowState::nsCSSInlineReflowState(nsCSSLineLayout& aLineLayout, nsCSSInlineFrame* aInlineFrame, nsIStyleContext* aInlineSC, const nsReflowState& aRS, - nsSize* aMaxElementSize) + PRBool aComputeMaxElementSize) : nsReflowState(aInlineFrame, *aRS.parentReflowState, aRS.maxSize), mInlineLayout(aLineLayout, aInlineFrame, aInlineSC) { @@ -52,10 +61,6 @@ nsCSSInlineReflowState::nsCSSInlineReflowState(nsCSSLineLayout& aLineLayout, aInlineSC->GetStyleData(eStyleStruct_Spacing); styleSpacing->CalcBorderPaddingFor(aInlineFrame, mBorderPadding); - if (nsnull != aMaxElementSize) { - aMaxElementSize->SizeTo(0, 0); - } - // If we're constrained adjust the available size so it excludes space // needed for border/padding nscoord width = maxSize.width; @@ -79,7 +84,7 @@ nsCSSInlineReflowState::nsCSSInlineReflowState(nsCSSLineLayout& aLineLayout, mInlineLayout.Init(this); mInlineLayout.Prepare(PRBool(NS_UNCONSTRAINEDSIZE == width), - mNoWrap, aMaxElementSize); + mNoWrap, aComputeMaxElementSize); mInlineLayout.SetReflowSpace(mBorderPadding.left, mBorderPadding.top, width, height/* XXX height??? */); } @@ -157,6 +162,12 @@ nsCSSInlineFrame::CreateContinuingFrame(nsIPresContext* aCX, return NS_OK; } +PRBool +nsCSSInlineFrame::DeleteNextInFlowsFor(nsIFrame* aChild) +{ + return DeleteChildsNextInFlow(aChild); +} + NS_IMETHODIMP nsCSSInlineFrame::FindTextRuns(nsCSSLineLayout& aLineLayout) { @@ -189,7 +200,8 @@ nsCSSInlineFrame::InlineReflow(nsCSSLineLayout& aLineLayout, } nsCSSInlineReflowState state(aLineLayout, this, mStyleContext, - aReflowState, aMetrics.maxElementSize); + aReflowState, + PRBool(nsnull != aMetrics.maxElementSize)); nsresult rv = NS_OK; if (eReflowReason_Initial == state.reason) { MoveOverflowToChildList(); @@ -297,9 +309,14 @@ nsCSSInlineFrame::ComputeFinalSize(nsCSSInlineReflowState& aState, } // Adjust max-element size if this frame's no-wrap flag is set. - if ((nsnull != aMetrics.maxElementSize) && aState.mNoWrap) { - aMetrics.maxElementSize->width = aMetrics.width; - aMetrics.maxElementSize->height = aMetrics.height; + if (aState.mInlineLayout.mComputeMaxElementSize) { + if (aState.mNoWrap) { + aMetrics.maxElementSize->width = aMetrics.width; + aMetrics.maxElementSize->height = aMetrics.height; + } + else { + *aMetrics.maxElementSize = aState.mInlineLayout.mMaxElementSize; + } } } @@ -315,23 +332,23 @@ nsCSSInlineFrame::FrameAppendedReflow(nsCSSInlineReflowState& aState) // XXX What about the case where the last frame is text or contains // text and we have just appended more text? - nsInlineReflowStatus rv = NS_INLINE_REFLOW_COMPLETE; + nsInlineReflowStatus rs = NS_INLINE_REFLOW_COMPLETE; if (0 != mChildCount) { - rv = ReflowMapped(aState); - if (IS_REFLOW_ERROR(rv)) { - return rv; + if (!ReflowMapped(aState, rs)) { + return rs; } } - if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rv)) { + if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rs)) { // Note: There is nothing to pullup because this is a // frame-appended reflow (therefore we are the last-in-flow) NS_ASSERTION(nsnull == mNextInFlow, "bad frame-appended-reflow"); // Reflow new children - rv = ReflowUnmapped(aState); + rs = ReflowUnmapped(aState); } - return rv; + + return rs; } nsInlineReflowStatus @@ -344,49 +361,51 @@ nsCSSInlineFrame::ChildIncrementalReflow(nsCSSInlineReflowState& aState) nsInlineReflowStatus nsCSSInlineFrame::ResizeReflow(nsCSSInlineReflowState& aState) { - nsInlineReflowStatus rv = NS_INLINE_REFLOW_COMPLETE; + nsInlineReflowStatus rs = NS_INLINE_REFLOW_COMPLETE; if (0 != mChildCount) { - rv = ReflowMapped(aState); - if (IS_REFLOW_ERROR(rv)) { - return rv; + if (!ReflowMapped(aState, rs)) { + return rs; } } - if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rv)) { + if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rs)) { // Try to fit some more children from our next in flow if (nsnull != mNextInFlow) { - rv = PullUpChildren(aState); + if (!PullUpChildren(aState, rs)) { + return rs; + } } } // XXX This is here temporarily until inline is reworked to // pre-fluff it's frame tree - if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rv)) { + if (NS_INLINE_REFLOW_COMPLETE == (NS_INLINE_REFLOW_REFLOW_MASK & rs)) { // Reflow new children - rv = ReflowUnmapped(aState); + rs = ReflowUnmapped(aState); } - return rv; + return rs; } -nsInlineReflowStatus -nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState) +PRBool +nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState, + nsInlineReflowStatus& aReflowStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsCSSInlineFrame::ReflowMapped: childCount=%d", mChildCount)); nsresult rv; - nsInlineReflowStatus reflowResult = NS_INLINE_REFLOW_NOT_COMPLETE; + + PRBool keepGoing = PR_FALSE; PRInt32 kidContentIndex = mFirstContentOffset; nsIFrame* prevChild = nsnull; nsIFrame* child = mFirstChild; while (nsnull != child) { - nsInlineReflowStatus rs = aState.mInlineLayout.ReflowAndPlaceFrame(child); - if (IS_REFLOW_ERROR(rs)) { - reflowResult = rs; - goto done; + aReflowStatus = aState.mInlineLayout.ReflowAndPlaceFrame(child); + if (IS_REFLOW_ERROR(aReflowStatus)) { + return PR_FALSE; } - switch (NS_INLINE_REFLOW_REFLOW_MASK & rs) { + switch (NS_INLINE_REFLOW_REFLOW_MASK & aReflowStatus) { case NS_INLINE_REFLOW_COMPLETE: prevChild = child; child->GetNextSibling(child); @@ -399,8 +418,8 @@ nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState) // won't know to create it. rv = MaybeCreateNextInFlow(aState, child); if (NS_OK != rv) { - reflowResult = nsInlineReflowStatus(rv); - goto done; + aReflowStatus = nsInlineReflowStatus(rv); + return PR_FALSE; } prevChild = child; child->GetNextSibling(child); @@ -423,9 +442,17 @@ nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState) child->GetNextSibling(child); if (nsnull != child) { PushKids(aState, prevChild, child); + aReflowStatus = NS_INLINE_REFLOW_NOT_COMPLETE; } else { - reflowResult = NS_INLINE_REFLOW_COMPLETE; + PRInt32 lastContentIndex; + lastContentIndex = mContent->ChildCount(); + if (++kidContentIndex == lastContentIndex) { + aReflowStatus = NS_INLINE_REFLOW_COMPLETE; + } + else { + aReflowStatus = NS_INLINE_REFLOW_NOT_COMPLETE; + } } goto done; @@ -434,6 +461,7 @@ nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState) if (nsnull != prevChild) { mLastContentOffset = kidContentIndex - 1; PushKids(aState, prevChild, child); + aReflowStatus = NS_INLINE_REFLOW_NOT_COMPLETE; } else { // We are trying to push our only child. It must be a block @@ -451,148 +479,19 @@ nsCSSInlineFrame::ReflowMapped(nsCSSInlineReflowState& aState) } NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); mLastContentIsComplete = PR_TRUE; + keepGoing = PR_TRUE; + +done:; aState.mLastChild = prevChild; - reflowResult = NS_INLINE_REFLOW_COMPLETE; - -done:; NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("exit nsCSSInlineFrame::ReflowMapped: childCount=%d reflowResult=%x", - mChildCount, reflowResult)); - return reflowResult; + ("exit nsCSSInlineFrame::ReflowMapped: childCount=%d rs=%x", + mChildCount, aReflowStatus)); + return keepGoing; } -nsInlineReflowStatus -nsCSSInlineFrame::ReflowUnmapped(nsCSSInlineReflowState& aState) -{ - NS_PRECONDITION(mLastContentIsComplete == PR_TRUE, "huh?"); - - nsresult rv; - nsInlineReflowStatus reflowResult = NS_INLINE_REFLOW_NOT_COMPLETE; - - // Get the childPrevInFlow for our eventual first child if we are a - // continuation and we have no children and the last child in our - // prev-in-flow is incomplete. While we are at it, we also compute - // our kidContentIndex. - PRInt32 kidContentIndex; - nsIFrame* childPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsCSSInlineFrame* prev = (nsCSSInlineFrame*)mPrevInFlow; - NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, - "bad prevInFlow"); - - kidContentIndex = prev->NextChildOffset(); - if (!prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(childPrevInFlow); - } - } - else { - kidContentIndex = NextChildOffset(); - } - - NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("enter nsCSSInlineFrame::ReflowUnmapped: kci=%d childPrevInFlow=%p", - kidContentIndex, childPrevInFlow)); - - nsIFrame* prevChild = aState.mLastChild; - PRInt32 lastContentIndex; - lastContentIndex = mContent->ChildCount(); - while (kidContentIndex < lastContentIndex) { - nsIContent* kid; - kid = mContent->ChildAt(kidContentIndex); - if (nsnull == kid) { - // Our content container is bad - break; - } - - // Create child - nsIFrame* child; - rv = nsHTMLBase::CreateFrame(aState.mPresContext, this, kid, - childPrevInFlow, child); - NS_RELEASE(kid); - if (NS_OK != rv) { - reflowResult = nsInlineReflowStatus(rv); - goto done; - } - if (nsnull == prevChild) { - mFirstChild = child; - mFirstContentOffset = kidContentIndex; - } - else { - prevChild->SetNextSibling(child); - } - mChildCount++; - NS_FRAME_TRACE(NS_FRAME_TRACE_NEW_FRAMES, - ("nsCSSInlineFrame::ReflowUnmapped: new-frame=%p prev-in-flow=%p", - child, childPrevInFlow)); - - // Reflow the child - nsInlineReflowStatus rs = aState.mInlineLayout.ReflowAndPlaceFrame(child); - if (IS_REFLOW_ERROR(rs)) { - reflowResult = rs; - goto done; - } - switch (NS_INLINE_REFLOW_REFLOW_MASK & rs) { - case NS_INLINE_REFLOW_COMPLETE: - prevChild = child; - childPrevInFlow = nsnull; - kidContentIndex++; - mLastContentIsComplete = PR_TRUE; - break; - - case NS_INLINE_REFLOW_NOT_COMPLETE: - // Note: We don't need to create a next-in-flow for the child - // because we know that we will be continued and our - // continuation will re-enter the reflow-unmapped logic and pick - // up from the prev-in-flows last child and continue it. - mLastContentOffset = kidContentIndex; - mLastContentIsComplete = PR_FALSE; - NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); - goto done; - - case NS_INLINE_REFLOW_BREAK_AFTER: - mLastContentOffset = kidContentIndex; - mLastContentIsComplete = PR_TRUE; - NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); - if (++kidContentIndex == lastContentIndex) { - reflowResult = NS_INLINE_REFLOW_COMPLETE; - } - goto done; - - case NS_INLINE_REFLOW_BREAK_BEFORE: - // We created the child but it turns out we can't keep it - mLastContentIsComplete = PR_TRUE; - if (nsnull != prevChild) { - mLastContentOffset = kidContentIndex - 1; - PushKids(aState, prevChild, child); - } - else { - // We are trying to push our only child. It must be a block - // that must be at the start of a line and we must not be at - // the start of a line. - NS_NOTYETIMPLEMENTED("XXX"); - } - goto done; - } - } - if (kidContentIndex == 0) { - NS_ASSERTION(lastContentIndex == 0, "bad kid content index"); - mLastContentOffset = 0; - } else { - mLastContentOffset = kidContentIndex - 1; - } - NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); - mLastContentIsComplete = PR_TRUE; - reflowResult = NS_INLINE_REFLOW_COMPLETE; - -done:; - NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("exit nsCSSInlineFrame::ReflowUnmapped: reflowResult=%x", reflowResult)); - return reflowResult; -} - -nsInlineReflowStatus -nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) +PRBool +nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState, + nsInlineReflowStatus& aReflowStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsCSSInlineFrame::PullUpChildren: childCount=%d", @@ -610,8 +509,9 @@ nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) kidContentIndex = NextChildOffset(); } + PRBool keepGoing = PR_FALSE; nsresult rv; - nsInlineReflowStatus reflowResult = NS_INLINE_REFLOW_NOT_COMPLETE; + aReflowStatus = NS_INLINE_REFLOW_COMPLETE; nsCSSInlineFrame* nextInFlow = (nsCSSInlineFrame*) mNextInFlow; nsIFrame* prevChild = aState.mLastChild; #ifdef NS_DEBUG @@ -635,12 +535,11 @@ nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) ("nsCSSInlineFrame::PullUpChildren: trying to pullup %p", child)); // Reflow it - nsInlineReflowStatus rs = aState.mInlineLayout.ReflowAndPlaceFrame(child); - if (IS_REFLOW_ERROR(rs)) { - reflowResult = rs; + aReflowStatus = aState.mInlineLayout.ReflowAndPlaceFrame(child); + if (IS_REFLOW_ERROR(aReflowStatus)) { goto done; } - switch (NS_INLINE_REFLOW_REFLOW_MASK & rs) { + switch (NS_INLINE_REFLOW_REFLOW_MASK & aReflowStatus) { case NS_INLINE_REFLOW_COMPLETE: prevChild = child; child->GetNextSibling(child); @@ -653,7 +552,7 @@ nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) // won't know to create it. rv = MaybeCreateNextInFlow(aState, child); if (NS_OK != rv) { - reflowResult = nsInlineReflowStatus(rv); + aReflowStatus = nsInlineReflowStatus(rv); goto done; } prevChild = child; @@ -668,18 +567,22 @@ nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) mLastContentOffset = kidContentIndex; mLastContentIsComplete = PR_TRUE; NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); + // XXX wrong! { PRInt32 lastContentIndex; lastContentIndex = mContent->ChildCount(); - if (kidContentIndex == lastContentIndex) { - // All of the children have been pulled up - reflowResult = NS_INLINE_REFLOW_COMPLETE; + if (++kidContentIndex == lastContentIndex) { + aReflowStatus = NS_INLINE_REFLOW_COMPLETE; + } + else { + aReflowStatus = NS_INLINE_REFLOW_NOT_COMPLETE; } } goto done; case NS_INLINE_REFLOW_BREAK_BEFORE: mLastContentIsComplete = PR_TRUE; + aReflowStatus = NS_INLINE_REFLOW_NOT_COMPLETE; // XXX wrong! if (nsnull != prevChild) { mLastContentOffset = kidContentIndex - 1; NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); @@ -701,23 +604,20 @@ nsCSSInlineFrame::PullUpChildren(nsCSSInlineReflowState& aState) } NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); mLastContentIsComplete = PR_TRUE; - reflowResult = NS_INLINE_REFLOW_COMPLETE; + keepGoing = PR_TRUE; done:; nextInFlow = (nsCSSInlineFrame*) mNextInFlow; if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { - if (NS_INLINE_REFLOW_COMPLETE != reflowResult) { - // XXX This is only necessary if we want to avoid setting the - // mFirstContentOffset when we get our first child. I think it's - // a bad trade. + if (NS_INLINE_REFLOW_COMPLETE != aReflowStatus) { AdjustOffsetOfEmptyNextInFlows(); } } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("exit nsCSSInlineFrame::PullUpChildren: childCount=%d reflowResult=%x", - mChildCount, reflowResult)); - return reflowResult; + ("exit nsCSSInlineFrame::PullUpChildren: childCount=%d rs=%x", + mChildCount, aReflowStatus)); + return keepGoing; } nsIFrame* @@ -794,6 +694,140 @@ nsCSSInlineFrame::MaybeCreateNextInFlow(nsCSSInlineReflowState& aState, return NS_OK; } +nsInlineReflowStatus +nsCSSInlineFrame::ReflowUnmapped(nsCSSInlineReflowState& aState) +{ + NS_PRECONDITION(mLastContentIsComplete == PR_TRUE, "huh?"); + + nsresult rv; + PRBool keepGoing = PR_FALSE; + nsInlineReflowStatus rs = NS_INLINE_REFLOW_COMPLETE; + + // Get the childPrevInFlow for our eventual first child if we are a + // continuation and we have no children and the last child in our + // prev-in-flow is incomplete. While we are at it, we also compute + // our kidContentIndex. + PRInt32 kidContentIndex; + nsIFrame* childPrevInFlow = nsnull; + if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { + nsCSSInlineFrame* prev = (nsCSSInlineFrame*)mPrevInFlow; + NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, + "bad prevInFlow"); + + kidContentIndex = prev->NextChildOffset(); + if (!prev->mLastContentIsComplete) { + // Our prev-in-flow's last child is not complete + prev->LastChild(childPrevInFlow); + } + } + else { + kidContentIndex = NextChildOffset(); + } + + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, + ("enter nsCSSInlineFrame::ReflowUnmapped: kci=%d childPrevInFlow=%p", + kidContentIndex, childPrevInFlow)); + + nsIFrame* prevChild = aState.mLastChild; + PRInt32 lastContentIndex; + lastContentIndex = mContent->ChildCount(); + while (kidContentIndex < lastContentIndex) { + nsIContent* kid; + kid = mContent->ChildAt(kidContentIndex); + if (nsnull == kid) { + // Our content container is bad + break; + } + + // Create child + nsIFrame* child; + rv = nsHTMLBase::CreateFrame(aState.mPresContext, this, kid, + childPrevInFlow, child); + NS_RELEASE(kid); + if (NS_OK != rv) { + rs = nsInlineReflowStatus(rv); + goto done; + } + if (nsnull == prevChild) { + mFirstChild = child; + mFirstContentOffset = kidContentIndex; + } + else { + prevChild->SetNextSibling(child); + } + mChildCount++; + NS_FRAME_TRACE(NS_FRAME_TRACE_NEW_FRAMES, + ("nsCSSInlineFrame::ReflowUnmapped: new-frame=%p prev-in-flow=%p", + child, childPrevInFlow)); + + // Reflow the child + rs = aState.mInlineLayout.ReflowAndPlaceFrame(child); + if (IS_REFLOW_ERROR(rs)) { + return rs; + } + switch (NS_INLINE_REFLOW_REFLOW_MASK & rs) { + case NS_INLINE_REFLOW_COMPLETE: + prevChild = child; + childPrevInFlow = nsnull; + kidContentIndex++; + mLastContentIsComplete = PR_TRUE; + break; + + case NS_INLINE_REFLOW_NOT_COMPLETE: + // Note: We don't need to create a next-in-flow for the child + // because we know that we will be continued and our + // continuation will re-enter the reflow-unmapped logic and pick + // up from the prev-in-flows last child and continue it. + mLastContentOffset = kidContentIndex; + mLastContentIsComplete = PR_FALSE; + NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); + goto done; + + case NS_INLINE_REFLOW_BREAK_AFTER: + mLastContentOffset = kidContentIndex; + mLastContentIsComplete = PR_TRUE; + NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); + // XXX wrong! + if (++kidContentIndex == lastContentIndex) { + rs = NS_INLINE_REFLOW_COMPLETE; + } + else { + rs = NS_INLINE_REFLOW_NOT_COMPLETE; + } + goto done; + + case NS_INLINE_REFLOW_BREAK_BEFORE: + // We created the child but it turns out we can't keep it + mLastContentIsComplete = PR_TRUE; + rs = NS_INLINE_REFLOW_NOT_COMPLETE; // XXX wrong! + if (nsnull != prevChild) { + mLastContentOffset = kidContentIndex - 1; + PushKids(aState, prevChild, child); + } + else { + // We are trying to push our only child. It must be a block + // that must be at the start of a line and we must not be at + // the start of a line. + NS_NOTYETIMPLEMENTED("XXX"); + } + goto done; + } + } + if (kidContentIndex == 0) { + NS_ASSERTION(lastContentIndex == 0, "bad kid content index"); + mLastContentOffset = 0; + } else { + mLastContentOffset = kidContentIndex - 1; + } + NS_ASSERTION(mFirstContentOffset <= mLastContentOffset, "bad fco/lco"); + mLastContentIsComplete = PR_TRUE; + +done:; + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, + ("exit nsCSSInlineFrame::ReflowUnmapped: rs=%x", rs)); + return rs; +} + void nsCSSInlineFrame::PushKids(nsCSSInlineReflowState& aState, nsIFrame* aPrevChild, nsIFrame* aPushedChild) diff --git a/mozilla/layout/css/layout/src/nsCSSInlineFrame.h b/mozilla/layout/css/layout/src/nsCSSInlineFrame.h index b293b1ecf11..479c7444821 100644 --- a/mozilla/layout/css/layout/src/nsCSSInlineFrame.h +++ b/mozilla/layout/css/layout/src/nsCSSInlineFrame.h @@ -33,7 +33,7 @@ struct nsCSSInlineReflowState : public nsReflowState { nsCSSInlineFrame* aInlineFrame, nsIStyleContext* aInlineSC, const nsReflowState& aReflowState, - nsSize* aMaxElementSize); + PRBool aComputeMaxElementSize); ~nsCSSInlineReflowState(); nsIPresContext* mPresContext; @@ -79,6 +79,9 @@ public: nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState); + // nsCSSContainerFrame + virtual PRBool DeleteNextInFlowsFor(nsIFrame* aChild); + protected: nsCSSInlineFrame(nsIContent* aContent, nsIFrame* aParent); @@ -95,15 +98,17 @@ protected: void ComputeFinalSize(nsCSSInlineReflowState& aState, nsReflowMetrics& aMetrics); - nsInlineReflowStatus ReflowMapped(nsCSSInlineReflowState& aState); + PRBool ReflowMapped(nsCSSInlineReflowState& aState, + nsInlineReflowStatus& aReflowStatus); - nsInlineReflowStatus ReflowUnmapped(nsCSSInlineReflowState& aState); - - nsInlineReflowStatus PullUpChildren(nsCSSInlineReflowState& aState); + PRBool PullUpChildren(nsCSSInlineReflowState& aState, + nsInlineReflowStatus& aReflowStatus); nsIFrame* PullOneChild(nsCSSInlineFrame* aNextInFlow, nsIFrame* aLastChild); + nsInlineReflowStatus ReflowUnmapped(nsCSSInlineReflowState& aState); + nsresult MaybeCreateNextInFlow(nsCSSInlineReflowState& aState, nsIFrame* aFrame); diff --git a/mozilla/layout/css/layout/src/nsCSSInlineLayout.cpp b/mozilla/layout/css/layout/src/nsCSSInlineLayout.cpp index 0b65added1d..6ee3fffb07f 100644 --- a/mozilla/layout/css/layout/src/nsCSSInlineLayout.cpp +++ b/mozilla/layout/css/layout/src/nsCSSInlineLayout.cpp @@ -25,17 +25,17 @@ #include "nsIFontMetrics.h" #include "nsIStyleContext.h" #include "nsIPresContext.h" +#include "nsIReflowCommand.h" #include "nsIRunaround.h" nsCSSInlineLayout::nsCSSInlineLayout(nsCSSLineLayout& aLineLayout, - nsIFrame* aContainerFrame, + nsCSSContainerFrame* aContainerFrame, nsIStyleContext* aContainerStyle) : mLineLayout(aLineLayout) { mContainerFrame = aContainerFrame; mAscents = mAscentBuf; mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]); - mMaxElementSize = nsnull; mContainerFont = (const nsStyleFont*) aContainerStyle->GetStyleData(eStyleStruct_Font); @@ -80,13 +80,18 @@ nsCSSInlineLayout::SetAscent(nscoord aAscent) } void -nsCSSInlineLayout::Prepare(PRBool aUnconstrainedWidth, PRBool aNoWrap, - nsSize* aMaxElementSize) +nsCSSInlineLayout::Prepare(PRBool aUnconstrainedWidth, + PRBool aNoWrap, + PRBool aComputeMaxElementSize) { mFrameNum = 0; mUnconstrainedWidth = aUnconstrainedWidth; mNoWrap = aNoWrap; - mMaxElementSize = aMaxElementSize; + mComputeMaxElementSize = aComputeMaxElementSize; + if (aComputeMaxElementSize) { + mMaxElementSize.width = 0; + mMaxElementSize.height = 0; + } mMaxAscent = 0; mMaxDescent = 0; } @@ -128,7 +133,13 @@ nsCSSInlineLayout::ReflowAndPlaceFrame(nsIFrame* aFrame) // reason will be wrong so we need to check the frame state. nsReflowReason reason = eReflowReason_Resize; if (nsnull != mContainerReflowState->reflowCommand) { - reason = eReflowReason_Incremental; + // If the reflow command was targeted at the container we are + // reflowing for, don't make the reason incremental. + nsIFrame* target; + mContainerReflowState->reflowCommand->GetTarget(target); + if (mContainerFrame != target) { + reason = eReflowReason_Incremental; + } } else { nsFrameState state; @@ -141,7 +152,10 @@ nsCSSInlineLayout::ReflowAndPlaceFrame(nsIFrame* aFrame) // Setup reflow state for reflowing the frame nsReflowState reflowState(aFrame, *mContainerReflowState, maxSize, reason); nsInlineReflowStatus rs; - nsReflowMetrics metrics(mMaxElementSize); + nsSize frameMaxElementSize; + nsReflowMetrics metrics(mComputeMaxElementSize + ? &frameMaxElementSize + : nsnull); PRBool isAware; aFrame->WillReflow(*mLineLayout.mPresContext); rs = ReflowFrame(aFrame, metrics, reflowState, isAware); @@ -152,6 +166,10 @@ nsCSSInlineLayout::ReflowAndPlaceFrame(nsIFrame* aFrame) return rs; } + if (!isAware && ((0 != metrics.width) || (0 != metrics.height))) { + mLineLayout.SetSkipLeadingWhiteSpace(PR_FALSE); + } + // It's possible the frame didn't fit if (metrics.width > maxSize.width) { if (!IsFirstChild()) { @@ -253,7 +271,7 @@ nsCSSInlineLayout::ReflowFrame(nsIFrame* aKidFrame, // parent is not this because we are executing pullup code) nsIFrame* parent; aKidFrame->GetGeometricParent(parent); - parent->DeleteChildsNextInFlow(aKidFrame); + ((nsCSSContainerFrame*)parent)->DeleteNextInFlowsFor(aKidFrame); } } @@ -302,6 +320,7 @@ nsCSSInlineLayout::PlaceFrame(nsIFrame* aFrame, } } } + nscoord totalWidth = 0; if (!isBullet) { // Place normal in-flow child aFrame->SetRect(aFrameRect); @@ -326,7 +345,7 @@ nsCSSInlineLayout::PlaceFrame(nsIFrame* aFrame, horizontalMargins = aFrameMargin.left + aFrameMargin.right; break; } - nscoord totalWidth = aFrameMetrics.width + horizontalMargins; + totalWidth = aFrameMetrics.width + horizontalMargins; mX += totalWidth; } @@ -336,21 +355,18 @@ nsCSSInlineLayout::PlaceFrame(nsIFrame* aFrame, aFrameRect.x, aFrameRect.y, aFrameRect.width, aFrameRect.height)); -#if XXX_fix_me // XXX this is not right; the max-element-size of a child depends on // it's margins which it doesn't know how to add in - if (nsnull != mMaxElementSize) { - // XXX I'm not certain that this is doing the right thing; rethink this - nscoord elementWidth = kidMaxElementSize->width + horizontalMargins; - if (elementWidth > mMaxElementSize->width) { - mMaxElementSize->width = elementWidth; + // Fold in child's max-element-size information into our own + if (mComputeMaxElementSize) { + if (aFrameMetrics.maxElementSize->width > mMaxElementSize.width) { + mMaxElementSize.width = aFrameMetrics.maxElementSize->width; } - if (aFrameMetrics.height > mMaxElementSize->height) { - mMaxElementSize->height = aFrameMetrics.height; + if (aFrameMetrics.maxElementSize->height > mMaxElementSize.height) { + mMaxElementSize.height = aFrameMetrics.maxElementSize->height; } } -#endif if (aFrameMetrics.ascent > mMaxAscent) { mMaxAscent = aFrameMetrics.ascent; @@ -364,22 +380,6 @@ nsCSSInlineLayout::PlaceFrame(nsIFrame* aFrame, } mFrameNum++; -#if XXX_fix_me - mLine->mLastContentOffset = mKidContentIndex; - switch (aFrameReflowStatus & NS_INLINE_REFLOW_REFLOW_MASK) { - case NS_INLINE_REFLOW_COMPLETE: - case NS_INLINE_REFLOW_BREAK_AFTER: - mLine->mLastContentIsComplete = PR_TRUE; - mKidPrevInFlow = nsnull; - break; - - case NS_INLINE_REFLOW_NOT_COMPLETE: - mLine->mLastContentIsComplete = PR_FALSE; - mKidPrevInFlow = mKidFrame; - break; - } -#endif - return aFrameReflowStatus; } diff --git a/mozilla/layout/css/layout/src/nsCSSInlineLayout.h b/mozilla/layout/css/layout/src/nsCSSInlineLayout.h index 4f3b2d368f0..13e5c633346 100644 --- a/mozilla/layout/css/layout/src/nsCSSInlineLayout.h +++ b/mozilla/layout/css/layout/src/nsCSSInlineLayout.h @@ -19,7 +19,7 @@ #ifndef nsCSSInlineLayout_h___ #define nsCSSInlineLayout_h___ -#include "nsIFrame.h" +#include "nsCSSContainerFrame.h" #include "nsIInlineReflow.h" class nsCSSLineLayout; struct nsStyleDisplay; @@ -34,7 +34,7 @@ struct nsStyleText; */ struct nsCSSInlineLayout { nsCSSInlineLayout(nsCSSLineLayout& aLineLayout, - nsIFrame* aContainerFrame, + nsCSSContainerFrame* aContainerFrame, nsIStyleContext* aContainerStyle); ~nsCSSInlineLayout(); @@ -42,7 +42,7 @@ struct nsCSSInlineLayout { void Prepare(PRBool aUnconstrainedWidth, PRBool aNoWrap, - nsSize* aMaxElementSize); + PRBool aComputeMaxElementSize); void SetReflowSpace(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); @@ -79,7 +79,7 @@ struct nsCSSInlineLayout { nsIFrame*& aNextInFlowResult); nsCSSLineLayout& mLineLayout; - nsIFrame* mContainerFrame; + nsCSSContainerFrame* mContainerFrame; const nsStyleFont* mContainerFont; const nsStyleText* mContainerText; const nsStyleDisplay* mContainerDisplay; @@ -88,6 +88,7 @@ struct nsCSSInlineLayout { PRPackedBool mUnconstrainedWidth; PRPackedBool mNoWrap; + PRPackedBool mComputeMaxElementSize; nscoord mAvailWidth; nscoord mAvailHeight; nscoord mX, mY; @@ -100,7 +101,7 @@ struct nsCSSInlineLayout { nscoord mMaxAscent; nscoord mMaxDescent; - nsSize* mMaxElementSize; + nsSize mMaxElementSize; }; #endif /* nsCSSInlineLayout_h___ */ diff --git a/mozilla/layout/css/layout/src/nsCSSLineLayout.cpp b/mozilla/layout/css/layout/src/nsCSSLineLayout.cpp index 344a67eeda9..b1cbf7ad613 100644 --- a/mozilla/layout/css/layout/src/nsCSSLineLayout.cpp +++ b/mozilla/layout/css/layout/src/nsCSSLineLayout.cpp @@ -59,6 +59,7 @@ nsCSSLineLayout::nsCSSLineLayout(nsIPresContext* aPresContext, mLineNumber = 0; mLeftEdge = 0; mColumn = 0; + mSkipLeadingWS = PR_TRUE; } nsCSSLineLayout::~nsCSSLineLayout() diff --git a/mozilla/layout/css/layout/src/nsCSSLineLayout.h b/mozilla/layout/css/layout/src/nsCSSLineLayout.h index df77b2aa66f..e0414863e74 100644 --- a/mozilla/layout/css/layout/src/nsCSSLineLayout.h +++ b/mozilla/layout/css/layout/src/nsCSSLineLayout.h @@ -72,6 +72,7 @@ public: void Prepare(nscoord aLeftEdge) { mLeftEdge = aLeftEdge; mColumn = 0; + mSkipLeadingWS = PR_TRUE; } PRInt32 GetColumn() { @@ -82,6 +83,10 @@ public: mColumn = aNewColumn; } + void NextLine() { + mLineNumber++; + } + nsIPresContext* mPresContext; nsISpaceManager* mSpaceManager; @@ -93,6 +98,15 @@ public: nsCSSTextRun* mTextRuns; nsCSSTextRun** mTextRunP; nsCSSTextRun* mCurrentTextRun; + + //XXX temporary? + + void SetSkipLeadingWhiteSpace(PRBool aNewSetting) { + mSkipLeadingWS = aNewSetting; + } + PRBool GetSkipLeadingWhiteSpace() { return mSkipLeadingWS; } + + PRBool mSkipLeadingWS; }; #endif /* nsCSSLineLayout_h___ */ diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h deleted file mode 100644 index 77b3e0ee8ff..00000000000 --- a/mozilla/layout/generic/nsBlockFrame.h +++ /dev/null @@ -1,313 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#ifndef nsBlockFrame_h___ -#define nsBlockFrame_h___ - -#include "nsHTMLContainerFrame.h" -#include "nsIFloaterContainer.h" -#include "nsIRunaround.h" -#include "nsISpaceManager.h" -#include "nsLineLayout.h" -#include "nsVoidArray.h" - -struct nsMargin; -struct nsStyleDisplay; -struct nsStyleFont; -struct nsStyleText; -class nsBlockFrame; -struct nsBandData; - -struct nsBlockBandData : public nsBandData { - // Trapezoids used during band processing - nsBandTrapezoid data[12]; - - // Bounding rect of available space between any left and right floaters - nsRect availSpace; - - nsBlockBandData() { - size = 12; - trapezoids = data; - } - - /** - * Computes the bounding rect of the available space, i.e. space - * between any left and right floaters Uses the current trapezoid - * data, see nsISpaceManager::GetBandData(). Also updates member - * data "availSpace". - */ - void ComputeAvailSpaceRect(); -}; - -struct nsBlockReflowState { - nsBlockReflowState(); - ~nsBlockReflowState(); - - nsresult Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock); - - nsresult RecoverState(nsLineData* aLine); - - nsIPresContext* mPresContext; - - nsBlockFrame* mBlock; - PRBool mBlockIsPseudo; - - // Current line being reflowed - nsLineLayout* mCurrentLine; - - // Previous line's last child frame - nsIFrame* mPrevKidFrame; - - // Layout position information - nscoord mX; - nscoord mY; - nsSize mAvailSize; - nsSize mStyleSize; - PRIntn mStyleSizeFlags; - PRPackedBool mUnconstrainedWidth; - PRPackedBool mUnconstrainedHeight; - nsSize* mMaxElementSizePointer; - nscoord mKidXMost; - const nsReflowState* reflowState; - - // Change in width since last reflow - nscoord mDeltaWidth; - - // Bottom margin information from the previous line (only when - // the previous line contains a block element) - nscoord mPrevNegBottomMargin; - nscoord mPrevPosBottomMargin; - PRBool mPrevMarginSynthetic; - - // Block frame border+padding information - nsMargin mBorderPadding; - - // Space manager and current band information - nsISpaceManager* mSpaceManager; - nsBlockBandData mCurrentBand; - - // Array of floaters to place below current line - nsVoidArray mPendingFloaters; - - // The next list ordinal for counting list bullets - PRInt32 mNextListOrdinal; - PRBool mListPositionOutside; -}; - -//---------------------------------------------------------------------- - -/* 94e8e410-de21-11d1-89bf-006008911b81 */ -#define NS_BLOCKFRAME_CID \ - {0x94e8e410, 0xde21, 0x11d1, {0x89, 0xbf, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} - -/** - *

Block Reflow

- * - * The block frame reflow machinery performs "2D" layout. Inline - * elements are flowed into logical lines (left to right or right to - * left) and the lines are stacked vertically. nsLineLayout is used - * for this part of the process. Block elements are flowed directly by - * the block reflow logic after flushing out any preceeding line.

- * - * During reflow, the block frame will make available to child frames - * it's reflow state using the presentation shell's cached data - * mechanism.

- * - *

Reflowing Mapped Content

- *

Pullup

- *

Reflowing Unmapped Content

- *

Content Insertion Handling

- *

Content Deletion Handling

- *

Style Change Handling

- * - *

Assertions

- * mLastContentIsComplete always reflects the state of the last - * child frame on our chlid list. - */ - -// XXX we don't use nsContainerFrame mOverFlowList!!! wasted memory - -class nsBlockFrame : public nsHTMLContainerFrame, - public nsIRunaround, - public nsIFloaterContainer -{ -public: - /** - * Create a new block frame that maps the given piece of content. - */ - static nsresult NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent); - - // nsISupports - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - - // nsIFrame - NS_IMETHOD ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer); - NS_IMETHOD ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent); - NS_IMETHOD ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent); - NS_IMETHOD ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent); - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics); - NS_IMETHOD IsSplittable(nsSplittableType& aIsSplittable) const; - NS_IMETHOD CreateContinuingFrame(nsIPresContext* aPresContext, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame); - NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const; - NS_IMETHOD ListTag(FILE* out) const; - NS_IMETHOD VerifyTree() const; - - // nsIRunaround - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus); - - // nsIFloaterContainer - virtual PRBool AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder); - virtual void PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder); - - // nsBlockFrame - nsresult ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); - - nsresult ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus); - - static nsBlockReflowState* FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame); - -protected: - nsBlockFrame(nsIContent* aContent, nsIFrame* aParent); - - virtual ~nsBlockFrame(); - - virtual PRIntn GetSkipSides() const; - - virtual void WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow); - - nsresult InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState); - - void ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect); - - nsLineData* LastLine(); - nsLineData* FindLine(nsIFrame* aFrame); - - nsresult IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds); - - void DestroyLines(); - - void DrainOverflowList(); - - nsLineData* CreateLineForOverflowList(nsIFrame* aOverflowList); - -#ifdef NS_DEBUG - nsresult VerifyLines(PRBool aFinalCheck) const; -#endif - - void ClearFloaters(nsBlockReflowState& aState, - PRUint8 aBreakType); - - nsresult PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine); - - PRBool IsLeftMostChild(nsIFrame* aFrame); - - void PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState); - void PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY); - - nsresult GetAvailableSpace(nsBlockReflowState& aState, nscoord aY); - - PRBool MoreToReflow(nsBlockReflowState& aState); - - nsresult PushLines(nsBlockReflowState& aState, - nsLineData* aLine); - - nsresult ReflowMapped(nsBlockReflowState& aState); - nsresult ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine); - - nsresult ReflowUnmapped(nsBlockReflowState& aState); - - nsLineData* GetFirstLine(); - - void ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame); - - void SetFirstChild(nsIFrame* aFirstChild) { - if (nsnull == mFirstChild) { - mFirstChild = aFirstChild; - } - } - - nsLineData* mLines; - nsVoidArray* mRunInFloaters; // placeholder frames for floaters to display - // at the top line - - friend struct nsLineLayout; -}; - -#endif /* nsBlockFrame_h___ */ diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index 12ea5df79c8..7905c8f03a0 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -207,62 +207,6 @@ static void AdjustIndexInParents(nsIFrame* aContainerFrame, } } -nsresult -nsHTMLContainerFrame::CreateFrameFor(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIStyleContext* aStyleContext, - nsIFrame*& aResult) -{ - // Get the style data for the frame - const nsStylePosition* position = (const nsStylePosition*) - aStyleContext->GetStyleData(eStyleStruct_Position); - const nsStyleDisplay* display = (const nsStyleDisplay*) - aStyleContext->GetStyleData(eStyleStruct_Display); - nsIFrame* frame = nsnull; - - // See whether it wants any special handling - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if (display->mFloats != NS_STYLE_FLOAT_NONE) { - rv = nsPlaceholderFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if ((NS_STYLE_OVERFLOW_SCROLL == display->mOverflow) || - (NS_STYLE_OVERFLOW_AUTO == display->mOverflow)) { - rv = NS_NewScrollFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { - rv = nsFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else { - // Ask the content delegate to create the frame - nsIContentDelegate* delegate = aContent->GetDelegate(aPresContext); - rv = delegate->CreateFrame(aPresContext, aContent, this, - aStyleContext, frame); - NS_RELEASE(delegate); - } - if (NS_OK == rv) { - // Wrap the frame in a view if necessary - rv = nsHTMLBase::CreateViewForFrame(aPresContext, frame, aStyleContext, - PR_FALSE); - } - aResult = frame; - return rv; -} - NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, @@ -321,7 +265,8 @@ NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIStyleContext* kidSC; kidSC = aPresContext->ResolveStyleContextFor(aChild, parent); nsIFrame* newFrame; - nsresult rv = parent->CreateFrameFor(aPresContext, aChild, kidSC, newFrame); +//XXX nsresult rv = parent->CreateFrameFor(aPresContext, aChild, kidSC, newFrame); + nsresult rv = nsHTMLBase::CreateFrame(aPresContext, this, aChild, nsnull, newFrame); if (NS_OK != rv) { return rv; } @@ -369,23 +314,25 @@ NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsresult nsHTMLContainerFrame::ProcessInitialReflow(nsIPresContext* aPresContext) { - const nsStyleDisplay* display = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsHTMLContainerFrame::ProcessInitialReflow: display=%d", - display->mDisplay)); - if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { - // This container is a list-item container. Therefore it needs a - // bullet content object. - nsIHTMLContent* bullet; - nsresult rv = NS_NewHTMLBullet(&bullet); - if (NS_OK != rv) { - return rv; - } + if (nsnull == mPrevInFlow) { + const nsStyleDisplay* display = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, + ("nsHTMLContainerFrame::ProcessInitialReflow: display=%d", + display->mDisplay)); + if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { + // This container is a list-item container. Therefore it needs a + // bullet content object. + nsIHTMLContent* bullet; + nsresult rv = NS_NewHTMLBullet(&bullet); + if (NS_OK != rv) { + return rv; + } - // Insert the bullet. Do not allow an incremental reflow operation - // to occur. - mContent->InsertChildAt(bullet, 0, PR_FALSE); + // Insert the bullet. Do not allow an incremental reflow operation + // to occur. + mContent->InsertChildAt(bullet, 0, PR_FALSE); + } } return NS_OK; diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.h b/mozilla/layout/generic/nsHTMLContainerFrame.h index aefa2feb007..c7d4a11a232 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.h +++ b/mozilla/layout/generic/nsHTMLContainerFrame.h @@ -56,12 +56,8 @@ protected: virtual PRIntn GetSkipSides() const = 0; - nsresult CreateFrameFor(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIStyleContext* aStyleContext, - nsIFrame*& aResult); - nsresult ProcessInitialReflow(nsIPresContext* aPresContext); }; #endif /* nsHTMLContainerFrame_h___ */ + diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp deleted file mode 100644 index 06a623a8d1b..00000000000 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ /dev/null @@ -1,1288 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsInlineFrame.h" -#include "nsBlockFrame.h" -#include "nsSize.h" -#include "nsIContent.h" -#include "nsIContentDelegate.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsCSSLayout.h" -#include "nsPlaceholderFrame.h" -#include "nsIReflowCommand.h" -#include "nsHTMLAtoms.h" -#include "nsAbsoluteFrame.h" -#include "nsLeafFrame.h" -#include "nsIPtr.h" - -// XXX To Do: -// 2. horizontal child margins -// 3. borders/padding and splitting -// 4. child relative positioning -// 5. absolutely positioned children -// 6. direction support -// 7. CSS line-height property - -/* XXX */ -#include "nsHTMLIIDs.h" -#include "nsBlockFrame.h" - -#define DEFAULT_ASCENT_LEN 10 - -NS_DEF_PTR(nsIStyleContext); -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIContentDelegate); - -class nsInlineState -{ -public: - const nsStyleFont* font; // style font - nsMargin borderPadding; // inner margin - nsSize mStyleSize; - PRIntn mStyleSizeFlags; - nsSize availSize; // available space in which to reflow (starts as max size minus insets) - nsSize* maxElementSize; // maximum element size (may be null) - nscoord x; // running x-offset (starts at left inner edge) - const nscoord y; // y-offset (top inner edge) - nscoord maxAscent; // max child ascent - nscoord maxDescent; // max child descent - nscoord* ascents; // ascent information for each child - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; - nsLineLayout* lineLayout; - PRBool atBreakPoint; - const nsReflowState& reflowState; - PRBool mNoWrap; - - // Constructor - nsInlineState(nsIPresContext* aPresContext, - nsIFrame* aInlineFrame, - const nsStyleFont* aStyleFont, - const nsMargin& aBorderPadding, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize) - : x(aBorderPadding.left), // determined by inner edge - y(aBorderPadding.top), // determined by inner edge - reflowState(aReflowState) - { - nsBlockReflowState* brs = - nsBlockFrame::FindBlockReflowState(aPresContext, aInlineFrame); - lineLayout = brs->mCurrentLine; - atBreakPoint = PR_TRUE; - - font = aStyleFont; - borderPadding = aBorderPadding; - - unconstrainedWidth = PRBool(reflowState.maxSize.width == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(reflowState.maxSize.height == NS_UNCONSTRAINEDSIZE); - - // If we're constrained adjust the available size so it excludes space - // needed for border/padding - availSize.width = reflowState.maxSize.width; - if (PR_FALSE == unconstrainedWidth) { - availSize.width -= aBorderPadding.left + aBorderPadding.right; - } - availSize.height = reflowState.maxSize.height; - if (PR_FALSE == unconstrainedHeight) { - availSize.height -= aBorderPadding.top + aBorderPadding.bottom; - } - - // Initialize max element size - maxElementSize = aMaxElementSize; - if (nsnull != maxElementSize) { - maxElementSize->SizeTo(0, 0); - } - - ascents = ascentBuf; - maxAscent = 0; - maxDescent = 0; - mNoWrap = PR_FALSE; - } - - void SetNumAscents(PRIntn aNumAscents) { - // We keep around ascent information so that we can vertically align - // children after we figure out how many children fit. - if (aNumAscents > DEFAULT_ASCENT_LEN) { - ascents = new nscoord[aNumAscents]; - } - } - - // Destructor - ~nsInlineState() { - if (ascents != ascentBuf) { - delete ascents; - } - } - -private: - nscoord ascentBuf[DEFAULT_ASCENT_LEN]; -}; - -///////////////////////////////////////////////////////////////////////////// -// - -nsresult nsInlineFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsInlineFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsInlineFrame::nsInlineFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ - NS_PRECONDITION(!IsPseudoFrame(), "can not be a pseudo frame"); -} - -nsInlineFrame::~nsInlineFrame() -{ -} - -nsReflowStatus -nsInlineFrame::ReflowChild(nsInlineState& aState, - nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState) -{ - nsReflowStatus status; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(*aState.lineLayout, aDesiredSize, aReflowState, status); - } - else { - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, status); - } - - if (NS_FRAME_IS_COMPLETE(status)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return status; -} - -void nsInlineFrame::PlaceChild(nsIFrame* aChild, - PRInt32 aIndex, - nsInlineState& aState, - const nsReflowMetrics& aChildSize, - const nsSize* aChildMaxElementSize) -{ - // Set the child's rect - aChild->SetRect(nsRect(aState.x, aState.y, aChildSize.width, aChildSize.height)); - - // Adjust the running x-offset - aState.x += aChildSize.width; - - // Update the array of ascents and the max ascent and descent - aState.ascents[aIndex] = aChildSize.ascent; - if (aChildSize.ascent > aState.maxAscent) { - aState.maxAscent = aChildSize.ascent; - } - if (aChildSize.descent > aState.maxDescent) { - aState.maxDescent = aChildSize.descent; - } - - // If we're constrained then update the available width - if (!aState.unconstrainedWidth) { - aState.availSize.width -= aChildSize.width; - } - - // Update the maximum element size - if (nsnull != aChildMaxElementSize) { - if (aChildMaxElementSize->width > aState.maxElementSize->width) { - aState.maxElementSize->width = aChildMaxElementSize->width; - } - if (aChildMaxElementSize->height > aState.maxElementSize->height) { - aState.maxElementSize->height = aChildMaxElementSize->height; - } - } -} - -// XXX an image shouldn't be allowed to continue a word but text -// should. hmmm. - -PRBool -nsInlineFrame::CanFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame) -{ - PRBool result = PR_TRUE; - aState.atBreakPoint = nsnull == aState.lineLayout->mBreakFrame; - if ((aState.availSize.width <= 0) && - (aChildFrame != mFirstChild) && (nsnull != mFirstChild)) { - // If we are at a breakable position then it's ok to be out of - // room. Otherwise the child is allowed to fit. - if (aState.atBreakPoint) { - result = PR_FALSE; - } - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsInlineFrame::CanFitChild: availSize=%d result=%s", - aState.availSize.width, result ? "true" : "false")); - return result; -} - -// XXX dup first-child check because of calling code not being nice! ick! -PRBool -nsInlineFrame::DidFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - nsReflowMetrics& aChildMetrics) -{ - if ((aChildMetrics.width > aState.availSize.width) && - (aChildFrame != mFirstChild) && (nsnull != mFirstChild)) { - // If we *were* at a breakable position then it's ok to be out of - // room. Otherwise the child is allowed to fit. - if (aState.atBreakPoint) { - return PR_FALSE; - } - } - return PR_TRUE; -} - -/** - * Reflow the frames we've already created - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @param aChildFrame the first child frame to reflow - * @param aChildIndex the first child frame's index in the frame list - * @return true if we successfully reflowed all the mapped children and false - * otherwise, e.g. we pushed children to the next in flow - */ -PRBool -nsInlineFrame::ReflowMappedChildrenFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - NS_PRECONDITION(nsnull != aChildFrame, "no children"); - - PRInt32 childCount = aChildIndex; - nsIFrame* prevKidFrame = nsnull; - - // Remember our original mLastContentIsComplete so that if we end up - // having to push children, we have the correct value to hand to - // PushChildren. - PRBool originalLastContentIsComplete = mLastContentIsComplete; - - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; - PRBool result = PR_TRUE; - - for (nsIFrame* kidFrame = aChildFrame; nsnull != kidFrame; ) { - // If the previous child just reflowed has indicated a pending - // break, stop reflowing our remaining children. This can only - // happen when a prev-in-flow has pushed some junk into this - // frame. - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - - result = PR_FALSE; - break; - } - - // If the frame being reflowed is not appropriate (e.g. a block - // frame) then we should stop! This can only happen when a - // prev-in-flow has pushed some junk into this frame. - const nsStyleDisplay* kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if ((NS_STYLE_DISPLAY_BLOCK == kidDisplay->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == kidDisplay->mDisplay)) { - if (mFirstChild != kidFrame) { - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - result = PR_FALSE; - break; - } - } - - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - nsReflowStatus status; - - // Reflow the child into the available space - PRBool room = CanFitChild(aPresContext, aState, kidFrame); - if (room) { - kidFrame->WillReflow(*aPresContext); - status = ReflowChild(aState, kidFrame, aPresContext, kidSize, kidReflowState); - } - - // Did the child fit? - if (!room || !DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child - - // Since we are giving the next-in-flow our last child, we - // give it our original mLastContentIsComplete too (in case we - // are pushing into an empty next-in-flow) - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - - result = PR_FALSE; - break; - } - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, childCount, aState, kidSize, pKidMaxElementSize); - childCount++; - - // Remember where we just were in case we end up pushing children - prevKidFrame = kidFrame; - - // Is the child complete? - mLastContentIsComplete = NS_FRAME_IS_COMPLETE(status); - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // No, the child isn't complete - nsIFrame* kidNextInFlow; - - kidFrame->GetNextInFlow(kidNextInFlow); - PRBool lastContentIsComplete = mLastContentIsComplete; - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a continuing - // frame. This hooks the child into the flow - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, - continuingFrame); - NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); - - // Add the continuing frame to the sibling list - nsIFrame* nextSib; - - kidFrame->GetNextSibling(nextSib); - continuingFrame->SetNextSibling(nextSib); - kidFrame->SetNextSibling(continuingFrame); - if (nsnull == nextSib) { - // Assume that the continuation frame we just created is - // complete, for now. It will get reflowed by our - // next-in-flow (we are going to push it now) - lastContentIsComplete = PR_TRUE; - } - } - - // We've used up all of our available space so push the remaining - // children to the next-in-flow - nsIFrame* nextSibling; - - kidFrame->GetNextSibling(nextSibling); - if (nsnull != nextSibling) { - PushChildren(nextSibling, kidFrame, lastContentIsComplete); - SetLastContentOffset(prevKidFrame); - } - result = PR_FALSE; - break; - } - - // Get the next child frame - kidFrame->GetNextSibling(kidFrame); - } - - // Update the child count member data - mChildCount = childCount; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); - - nsIFrame* lastChild; - PRInt32 lastIndexInParent; - - LastChild(lastChild); - lastChild->GetContentIndex(lastIndexInParent); - NS_POSTCONDITION(lastIndexInParent == mLastContentOffset, "bad last content offset"); - VerifyLastIsComplete(); - } -#endif - return result; -} - -/** - * Try and pull-up frames from our next-in-flow - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @return true if we successfully pulled-up all the children and false - * otherwise, e.g. child didn't fit - */ -PRBool nsInlineFrame::PullUpChildren(nsIPresContext* aPresContext, - nsInlineState& aState) -{ - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("enter nsInlineFrame::PullUpChildren: [%d,%d,%c] childCount=%d", - mFirstContentOffset, - mLastContentOffset, - mLastContentIsComplete ? 'T' : 'F', - mChildCount)); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - - nsInlineFrame* nextInFlow = (nsInlineFrame*)mNextInFlow; - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; -#ifdef NS_DEBUG - PRInt32 kidIndex = NextChildOffset(); -#endif - nsIFrame* prevKidFrame; - - LastChild(prevKidFrame); - - PRBool result = PR_TRUE; - - while (nsnull != nextInFlow) { - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowStatus status; - - // Get the next child - nsIFrame* kidFrame = nextInFlow->mFirstChild; - - // Any more child frames? - if (nsnull == kidFrame) { - // No. Any frames on its overflow list? - if (nsnull != nextInFlow->mOverflowList) { - // Move the overflow list to become the child list - NS_ABORT(); - nextInFlow->AppendChildren(nextInFlow->mOverflowList); - nextInFlow->mOverflowList = nsnull; - kidFrame = nextInFlow->mFirstChild; - } else { - // We've pulled up all the children, so move to the next-in-flow. - nextInFlow = (nsInlineFrame*)nextInFlow->mNextInFlow; - continue; - } - } - - // It's time to stop pulling up if our last child wants a break - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - result = PR_FALSE; - break; - } - - // If the frame being pulled up is not appropriate (e.g. a block - // frame) then we should stop! - const nsStyleDisplay* kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if ((NS_STYLE_DISPLAY_BLOCK == kidDisplay->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == kidDisplay->mDisplay)) { - result = PR_FALSE; - break; - } - - // If there is no room, stop pulling up - if (!CanFitChild(aPresContext, aState, kidFrame)) { - result = PR_FALSE; - break; - } - -// XXX inline reflow avoidance will be done by nsLineLayout -#if XXX - // See if the child fits in the available space. If it fits or - // it's splittable then reflow it. The reason we can't just move - // it is that we still need ascent/descent information - nsSize kidFrameSize; - nsSplittableType kidIsSplittable; - - kidFrame->GetSize(kidFrameSize); - kidFrame->IsSplittable(kidIsSplittable); - if ((kidFrameSize.width > aState.availSize.width) && - NS_FRAME_IS_NOT_SPLITTABLE(kidIsSplittable)) { - result = PR_FALSE; - break; - } -#endif - - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - kidFrame->WillReflow(*aPresContext); - status = ReflowChild(aState, kidFrame, aPresContext, kidSize, kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child - result = PR_FALSE; - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsInlineFrame::PullUpChildren: pulled frame=%p [%c][%x]", - kidFrame, - NS_FRAME_IS_COMPLETE(status) ? 'T' : 'F', - status)); - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); - - // Remove the frame from its current parent - kidFrame->GetNextSibling(nextInFlow->mFirstChild); - nextInFlow->mChildCount--; - // Update the next-in-flows first content offset - if (nsnull != nextInFlow->mFirstChild) { - nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild); - } - - // Link the frame into our list of children - kidFrame->SetGeometricParent(this); - nsIFrame* kidContentParent; - - kidFrame->GetContentParent(kidContentParent); - if (nextInFlow == kidContentParent) { - kidFrame->SetContentParent(this); - } - if (nsnull == prevKidFrame) { - mFirstChild = kidFrame; - SetFirstContentOffset(kidFrame); - } else { - prevKidFrame->SetNextSibling(kidFrame); - } - kidFrame->SetNextSibling(nsnull); - mChildCount++; - prevKidFrame = kidFrame; - - // Is the child we just pulled up complete? - mLastContentIsComplete = NS_FRAME_IS_COMPLETE(status); - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // No the child isn't complete - nsIFrame* kidNextInFlow; - - kidFrame->GetNextInFlow(kidNextInFlow); - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a - // continuing frame. The creation appends it to the flow and - // prepares it for reflow. - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, - continuingFrame); - NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); - - // Add the continuing frame to our sibling list and then push - // it to the next-in-flow. This ensures the next-in-flow's - // content offsets and child count are set properly. Note that - // we can safely assume that the continuation is complete so - // we pass PR_TRUE into PushChidren in case our next-in-flow - // was just drained and now needs to know it's - // mLastContentIsComplete state. - kidFrame->SetNextSibling(continuingFrame); - - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsInlineFrame::PullUpChildren: pushing frame=%p", - continuingFrame)); - PushChildren(continuingFrame, kidFrame, PR_TRUE); - - // After we push the continuation frame we don't need to fuss - // with mLastContentIsComplete beause the continuation frame - // is no longer on *our* list. - } - - // If the child isn't complete then it means that we've used up - // all of our available space. - result = PR_FALSE; - break; - } - } - - // Update our last content offset - if (nsnull != prevKidFrame) { - NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child"); - SetLastContentOffset(prevKidFrame); - } - - // We need to make sure the first content offset is correct for any empty - // next-in-flow frames (frames where we pulled up all the child frames) - nextInFlow = (nsInlineFrame*)mNextInFlow; - if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { - // We have at least one empty frame. Did we succesfully pull up all the - // child frames? - if (PR_FALSE == result) { - // No, so we need to adjust the first content offset of all the empty - // frames - AdjustOffsetOfEmptyNextInFlows(); -#ifdef NS_DEBUG - } else { - // Yes, we successfully pulled up all the child frames which means all - // the next-in-flows must be empty. Do a sanity check - if (GetVerifyTreeEnable()) { - while (nsnull != nextInFlow) { - NS_ASSERTION(nsnull == nextInFlow->mFirstChild, - "non-empty next-in-flow"); - nextInFlow = (nsInlineFrame*)nextInFlow->mNextInFlow; - } - } -#endif - } - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("exit nsInlineFrame::PullUpChildren: [%d,%d,%c] childCount=%d", - mFirstContentOffset, - mLastContentOffset, - mLastContentIsComplete ? 'T' : 'F', - mChildCount)); - return result; -} - -/** - * Create new frames for content we haven't yet mapped - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @return NS_FRAME_COMPLETE if all content has been mapped and 0 if we - * should be continued - */ -nsReflowStatus -nsInlineFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, - nsInlineState& aState) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - nsIFrame* kidPrevInFlow = nsnull; - nsReflowStatus result = NS_FRAME_NOT_COMPLETE; - - // If we have no children and we have a prev-in-flow then we need to pick - // up where it left off. If we have children, e.g. we're being resized, then - // our content offset should already be set correctly... - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsInlineFrame* prev = (nsInlineFrame*)mPrevInFlow; - NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, - "bad prevInFlow"); - - mFirstContentOffset = prev->NextChildOffset(); - if (!prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - mLastContentIsComplete = PR_TRUE; - - // Place our children, one at a time until we are out of children - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = - (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; - PRInt32 kidIndex = NextChildOffset(); - nsIFrame* prevKidFrame; - - PRBool breakAfter = PR_FALSE; - LastChild(prevKidFrame); - for (;;) { - // Get the next content object - nsIContentPtr kid = mContent->ChildAt(kidIndex); - if (kid.IsNull()) { - result = NS_FRAME_COMPLETE; - break; - } - - // It's time to stop pulling up if our previous child wants a line - // break - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - break; - } - - // Make sure we still have room left - if (!CanFitChild(aPresContext, aState, nsnull)) { - // Note: return status was set to 0 above... - break; - } - - // Resolve style for the child - nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); - - // Figure out how we should treat the child - nsIFrame* kidFrame; - const nsStyleDisplay* kidDisplay = - (const nsStyleDisplay*)kidStyleContext->GetStyleData(eStyleStruct_Display); - const nsStylePosition* kidPosition = (const nsStylePosition*) - kidStyleContext->GetStyleData(eStyleStruct_Position); - - // Check whether it wants to floated or absolutely positioned - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == kidPosition->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - } else if (kidDisplay->mFloats != NS_STYLE_FLOAT_NONE) { - rv = nsPlaceholderFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - } else if (nsnull == kidPrevInFlow) { - nsIContentDelegatePtr kidDel; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - if (kidIndex != mFirstContentOffset) { - // We don't allow block elements to be placed in us anywhere - // other than at our left margin. - goto done; - } - // FALLTHROUGH - - case NS_STYLE_DISPLAY_INLINE: - kidDel = kid->GetDelegate(aPresContext); - rv = kidDel->CreateFrame(aPresContext, kid, this, - kidStyleContext, kidFrame); - break; - - default: - NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); - rv = nsFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - break; - } - } else { - rv = kidPrevInFlow->CreateContinuingFrame(aPresContext, this, - kidStyleContext, kidFrame); - } - - // Try to reflow the child into the available space. It might not - // fit or might need continuing. - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - kidFrame->WillReflow(*aPresContext); - nsReflowStatus status = ReflowChild(aState, kidFrame, aPresContext, kidSize, - kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child. Add the frame to our overflow list - NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); - mOverflowList = kidFrame; - prevKidFrame->SetNextSibling(nsnull); - break; - } - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); - - // Link child frame into the list of children - if (nsnull != prevKidFrame) { - prevKidFrame->SetNextSibling(kidFrame); - } else { - mFirstChild = kidFrame; // our first child - SetFirstContentOffset(kidFrame); - } - prevKidFrame = kidFrame; - mChildCount++; - kidIndex++; - - // Did the child complete? - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // If the child isn't complete then it means that we've used up - // all of our available space - mLastContentIsComplete = PR_FALSE; - break; - } - kidPrevInFlow = nsnull; - - // If we need to break after the kidFrame, then do so now - if (breakAfter) { - break; - } - } - -done:; - // Update the content mapping - NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child"); - SetLastContentOffset(prevKidFrame); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(len == mChildCount, "bad child count"); - VerifyLastIsComplete(); - } -#endif - return result; -} - -void -nsInlineFrame::InitializeState(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, - nsInlineState& aState) -{ - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - // When we are given a width, change the reflow behavior to - // unconstrained. - aState.unconstrainedWidth = PR_TRUE; - aState.availSize.width = NS_UNCONSTRAINEDSIZE; - } -} - -NS_METHOD nsInlineFrame::Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("enter nsInlineFrame::Reflow: this=%p: childCount=%d", - this, mChildCount)); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PreReflowCheck(); - } -#endif - - if (eReflowReason_Initial == aReflowState.reason) { - nsresult rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - - PRBool reflowMappedOK = PR_TRUE; - - aStatus = NS_FRAME_COMPLETE; // initialize out parameter - - // Get the style molecule - const nsStyleFont* styleFont = (const nsStyleFont*) - mStyleContext->GetStyleData(eStyleStruct_Font); - const nsStyleSpacing* styleSpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStyleText* styleText = (const nsStyleText*) - mStyleContext->GetStyleData(eStyleStruct_Text); - - // Check for an overflow list - if (eReflowReason_Incremental != aReflowState.reason) { - MoveOverflowToChildList(); - } - - // Initialize our reflow state. We must wait until after we've processed - // the overflow list, because our first content offset might change - nsMargin borderPadding; - styleSpacing->CalcBorderPaddingFor(this, borderPadding); - nsInlineState state(aPresContext, this, styleFont, borderPadding, - aReflowState, aDesiredSize.maxElementSize); - InitializeState(aPresContext, aReflowState, state); - state.SetNumAscents(mContent->ChildCount() - mFirstContentOffset); - state.mNoWrap = NS_STYLE_WHITESPACE_NORMAL != styleText->mWhiteSpace; - - if (eReflowReason_Incremental == aReflowState.reason) { - NS_ASSERTION(nsnull != aReflowState.reflowCommand, "null reflow command"); - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - - if (target == this) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - switch (type) { - case nsIReflowCommand::FrameAppended: - // Recover our state - RecoverState(aPresContext, state, nsnull); - aStatus = ReflowUnmappedChildren(aPresContext, state); - break; - - default: - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - break; - } - - } else { - // The command is passing through us. Get the next frame in the reflow chain - nsIFrame* kidFrame; - aReflowState.reflowCommand->GetNext(kidFrame); - - nsReflowMetrics kidSize(aDesiredSize.maxElementSize); - nsReflowState kidReflowState(kidFrame, aReflowState, state.availSize); - - // Restore our state as if nextFrame is the next frame to reflow - PRInt32 kidIndex = RecoverState(aPresContext, state, kidFrame); - - // Reflow the child into the available space - kidFrame->WillReflow(*aPresContext); - aStatus = ReflowChild(state, kidFrame, aPresContext, kidSize, kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, state, kidFrame, kidSize)) { - nsIFrame* prevFrame; - - // The child is too wide to fit in the available space, and - // it's not our first child - PrevChild(kidFrame, prevFrame); - PushChildren(kidFrame, prevFrame, mLastContentIsComplete); - SetLastContentOffset(prevFrame); - mChildCount = kidIndex - 1; - aStatus = NS_FRAME_NOT_COMPLETE; - - } else { - // Place and size the child - PlaceChild(kidFrame, kidIndex, state, kidSize, nsnull); - - nsIFrame* kidNextInFlow; - kidFrame->GetNextInFlow(kidNextInFlow); - - // Is the child complete? - if (NS_FRAME_IS_COMPLETE(aStatus)) { - // Check whether the frame has next-in-flow(s) that are no longer needed - if (nsnull != kidNextInFlow) { - // Remove the next-in-flow(s) - DeleteChildsNextInFlow(kidFrame); - } - - // Adjust the frames that follow - aStatus = IncrementalReflowAfter(aPresContext, state, kidFrame, kidIndex); - - } else { - nsIFrame* nextSibling; - - // No, the child isn't complete - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a continuing - // frame. - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, continuingFrame); - - // Link the child into the sibling list - kidFrame->GetNextSibling(nextSibling); - continuingFrame->SetNextSibling(nextSibling); - kidFrame->SetNextSibling(continuingFrame); - } - - // We've used up all of our available space, so push the remaining - // children to the next-in-flow - kidFrame->GetNextSibling(nextSibling); - if (nsnull != nextSibling) { - PushChildren(nextSibling, kidFrame, mLastContentIsComplete); - } - - SetLastContentOffset(kidFrame); - mChildCount = kidIndex; - } - } - } - - } else { - // Reflow any existing frames - if (nsnull != mFirstChild) { - reflowMappedOK = ReflowMappedChildrenFrom(aPresContext, state, mFirstChild, 0); - - if (PR_FALSE == reflowMappedOK) { - // We didn't successfully reflow our mapped frames; therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } - - // Did we successfully relow our mapped children? - if (PR_TRUE == reflowMappedOK) { -#if XXX - // Any space left? - if (state.availSize.width <= 0) { - // No space left. Don't try to pull-up children or reflow unmapped - if (NextChildOffset() < mContent->ChildCount()) { - // No room left to map the remaining content; therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } else -#endif - if (NextChildOffset() < mContent->ChildCount()) { - // Try and pull-up some children from a next-in-flow - if (PullUpChildren(aPresContext, state)) { - // If we still have unmapped children then create some new frames - if (NextChildOffset() < mContent->ChildCount()) { - aStatus = ReflowUnmappedChildren(aPresContext, state); - } - } else { - // We were unable to pull-up all the existing frames from the next in flow; - // therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } - } - - #if 0 - // XXX I don't think our return size properly accounts for the lineHeight - // (which may not == state.maxAscent + state.maxDescent) - // Return our size and our status - #endif - } - - // Vertically align the children - nscoord lineHeight = - nsCSSLayout::VerticallyAlignChildren(aPresContext, this, styleFont, - borderPadding.top, - mFirstChild, mChildCount, - state.ascents, state.maxAscent); - - ComputeFinalSize(aPresContext, state, aDesiredSize); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("exit nsInlineFrame::Reflow: this=%p: childCount=%d status=%scomplete", - this, mChildCount, - NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ")); - return NS_OK; -} - -void -nsInlineFrame::ComputeFinalSize(nsIPresContext* aPresContext, - nsInlineState& aState, - nsReflowMetrics& aDesiredSize) -{ - // Compute default size - aDesiredSize.width = aState.x + aState.borderPadding.right; - aDesiredSize.ascent = aState.borderPadding.top + aState.maxAscent; - aDesiredSize.descent = aState.maxDescent + aState.borderPadding.bottom; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - // Apply width/height style properties - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aDesiredSize.width = aState.borderPadding.left + aState.mStyleSize.width + - aState.borderPadding.right; - } - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredSize.height = aState.borderPadding.top + aState.mStyleSize.height + - aState.borderPadding.bottom; - } - - if ((nsnull != aDesiredSize.maxElementSize) && aState.mNoWrap) { - aDesiredSize.maxElementSize->width = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; - } -} - -///////////////////////////////////////////////////////////////////////////// - -PRIntn nsInlineFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_LEFT; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_RIGHT; - } - return skip; -} - -///////////////////////////////////////////////////////////////////////////// - -// Incremental reflow support - -NS_METHOD nsInlineFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nscoord maxAscent = 0; - nscoord maxDescent = 0; - nsIFrame* kid = mFirstChild; - while (nsnull != kid) { - // XXX Properly handle max element size... - nsReflowMetrics kidMetrics(aMetrics.maxElementSize); - kid->GetReflowMetrics(aPresContext, kidMetrics); - if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; - if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; - kid->GetNextSibling(kid); - } - - // XXX what about border & padding - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = maxAscent; - aMetrics.descent = maxDescent; - - return NS_OK; -} - -/** - * Setup aState to the state it would have had we just reflowed our - * children up to, but not including, aSkipChild. Return the index - * of aSkipChild in our list of children. - * If aSkipChild is nsnull then resets the state for appended content. - */ -PRInt32 nsInlineFrame::RecoverState(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aSkipChild) -{ - // Get ascent & descent info for all the children up to but not - // including aSkipChild. Also compute the x coordinate for where - // aSkipChild will be place after it is reflowed. - PRInt32 i = 0; - nsIFrame* kid = mFirstChild; - nscoord x = aState.x; - nscoord maxAscent = 0; - nscoord maxDescent = 0; - while ((nsnull != kid) && (kid != aSkipChild)) { - nsReflowMetrics kidMetrics(nsnull); - kid->GetReflowMetrics(aPresContext, kidMetrics); - aState.ascents[i] = kidMetrics.ascent; - if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; - if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; - - // XXX Factor in left and right margins - x += kidMetrics.width; - - kid->GetNextSibling(kid); - i++; - } - aState.maxAscent = maxAscent; - aState.maxDescent = maxDescent; - aState.x = x; - return i; -} - -// XXX We need to return information about whether our next-in-flow is -// dirty... -nsReflowStatus -nsInlineFrame::IncrementalReflowFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ - nsReflowStatus status = NS_FRAME_COMPLETE; - - // Just reflow all the mapped children starting with childFrame. - // XXX This isn't the optimal thing to do... - if (ReflowMappedChildrenFrom(aPresContext, aState, aChildFrame, aChildIndex)) { - if (NextChildOffset() < mContent->ChildCount()) { -#if XXX - // Any space left? - if (aState.availSize.width <= 0) { - // No space left. Don't try to pull-up children - status = NS_FRAME_NOT_COMPLETE; - } else -#endif - { - // Try and pull-up some children from a next-in-flow - if (!PullUpChildren(aPresContext, aState)) { - // We were not able to pull-up all the child frames from our - // next-in-flow - status = NS_FRAME_NOT_COMPLETE; - } - } - } - } else { - // We were unable to reflow all our mapped frames - status = NS_FRAME_NOT_COMPLETE; - } - - return status; -} - -nsReflowStatus -nsInlineFrame::IncrementalReflowAfter(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ - nsReflowStatus status = NS_FRAME_COMPLETE; - nsIFrame* nextFrame; - - aChildFrame->GetNextSibling(nextFrame); - - // Just reflow all the remaining mapped children - // XXX This isn't the optimal thing to do... - if ((nsnull == nextFrame) || - ReflowMappedChildrenFrom(aPresContext, aState, nextFrame, aChildIndex + 1)) { - if (NextChildOffset() < mContent->ChildCount()) { -#if XXX - // Any space left? - if (aState.availSize.width <= 0) { - // No space left. Don't try to pull-up children - status = NS_FRAME_NOT_COMPLETE; - } else -#endif - { - // Try and pull-up some children from a next-in-flow - if (!PullUpChildren(aPresContext, aState)) { - // We were not able to pull-up all the child frames from our - // next-in-flow - status = NS_FRAME_NOT_COMPLETE; - } - } - } - } else { - // We were unable to reflow all our mapped frames - status = NS_FRAME_NOT_COMPLETE; - } - - return status; -} - -// In order to execute the vertical alignment code after incremental -// reflow of the inline frame, we need to reposition any child frames -// that were relatively positioned back to their computed x origin. -// This should probably be done as a pre-alignment computation (and it -// can be avoided if there are no relatively positioned children). diff --git a/mozilla/layout/generic/nsLeafFrame.cpp b/mozilla/layout/generic/nsLeafFrame.cpp index cb98d4125ea..601c890906d 100644 --- a/mozilla/layout/generic/nsLeafFrame.cpp +++ b/mozilla/layout/generic/nsLeafFrame.cpp @@ -60,6 +60,7 @@ NS_METHOD nsLeafFrame::Reflow(nsIPresContext* aPresContext, // XXX add in code to check for width/height being set via css // and if set use them instead of calling GetDesiredSize. + GetDesiredSize(aPresContext, aReflowState, aDesiredSize); AddBordersAndPadding(aPresContext, aDesiredSize); if (nsnull != aDesiredSize.maxElementSize) { diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp deleted file mode 100644 index 1b651ec97b3..00000000000 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ /dev/null @@ -1,1695 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsLineLayout.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsBlockFrame.h" -#include "nsIContent.h" -#include "nsIContentDelegate.h" -#include "nsIPresContext.h" -#include "nsISpaceManager.h" -#include "nsIPtr.h" -#include "nsAbsoluteFrame.h" -#include "nsPlaceholderFrame.h" -#include "nsCSSLayout.h" -#include "nsCRT.h" -#include "nsIReflowCommand.h" -#include "nsIFontMetrics.h" -#include "nsHTMLBase.h" -#include "nsScrollFrame.h" - -#undef NOISY_REFLOW - -// XXX zap mAscentNum - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -nsLineData::nsLineData() -{ - mNextLine = nsnull; - mPrevLine = nsnull; - mFirstChild = nsnull; - mChildCount = 0; - mFirstContentOffset = 0; - mLastContentOffset = 0; - mLastContentIsComplete = PR_TRUE; - mIsBlock = PR_FALSE; - mBounds.SetRect(0, 0, 0, 0); - mFloaters = nsnull; -} - -nsLineData::~nsLineData() -{ - delete mFloaters; -} - -void -nsLineData::UnlinkLine() -{ - nsLineData* prevLine = mPrevLine; - nsLineData* nextLine = mNextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; -} - -nsresult -nsLineData::Verify(PRBool aFinalCheck) const -{ - NS_ASSERTION(mNextLine != this, "bad line linkage"); - NS_ASSERTION(mPrevLine != this, "bad line linkage"); - if (nsnull != mPrevLine) { - NS_ASSERTION(mPrevLine->mNextLine == this, "bad line linkage"); - } - if (nsnull != mNextLine) { - NS_ASSERTION(mNextLine->mPrevLine == this, "bad line linkage"); - } - - if (aFinalCheck) { - NS_ASSERTION(0 != mChildCount, "empty line"); - NS_ASSERTION(nsnull != mFirstChild, "empty line"); - - nsIFrame* nextLinesFirstChild = nsnull; - if (nsnull != mNextLine) { - nextLinesFirstChild = mNextLine->mFirstChild; - } - - // Check that number of children are ok and that the index in parent - // information agrees with the content offsets. - PRInt32 offset = mFirstContentOffset; - PRInt32 len = 0; - nsIFrame* child = mFirstChild; - while ((nsnull != child) && (child != nextLinesFirstChild)) { - PRInt32 indexInParent; - child->GetContentIndex(indexInParent); - NS_ASSERTION(indexInParent == offset, "bad line offsets"); - len++; - if (len != mChildCount) { - offset++; - } - child->GetNextSibling(child); - } - NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset"); - NS_ASSERTION(len == mChildCount, "bad child count"); - } - - if (1 == mChildCount) { - if (mIsBlock) { - nsIFrame* child = mFirstChild; - const nsStyleDisplay* display; - child->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - NS_ASSERTION((NS_STYLE_DISPLAY_BLOCK == display->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay), - "bad mIsBlock state"); - } - } - - // XXX verify content offsets and mLastContentIsComplete - return NS_OK; -} - -nsIFrame* -nsLineData::GetLastChild() -{ - nsIFrame* lastChild = mFirstChild; - if (mChildCount > 1) { - for (PRInt32 numKids = mChildCount - 1; --numKids >= 0; ) { - nsIFrame* nextChild; - lastChild->GetNextSibling(nextChild); - lastChild = nextChild; - } - } - return lastChild; -} - -PRIntn -nsLineData::GetLineNumber() const -{ - PRIntn lineNumber = 0; - nsLineData* prev = mPrevLine; - while (nsnull != prev) { - lineNumber++; - prev = prev->mPrevLine; - } - return lineNumber; -} - -void -nsLineData::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the first/last content offset - fprintf(out, "line %d [%d,%d,%c] ", - GetLineNumber(), - mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - - // Output the bounds rect - out << mBounds; - - // Output the children, one line at a time - if (nsnull != mFirstChild) { - fputs("<\n", out); - aIndent++; - - nsIFrame* child = mFirstChild; - for (PRInt32 numKids = mChildCount; --numKids >= 0; ) { - child->List(out, aIndent); - child->GetNextSibling(child); - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - fputs("<>\n", out); - } -} - -//---------------------------------------------------------------------- - -nsLineLayout::nsLineLayout(nsBlockReflowState& aState) - : mBlockReflowState(aState) -{ - mBlock = aState.mBlock; - mSpaceManager = aState.mSpaceManager; - mBlock->GetContent(mBlockContent); - mPresContext = aState.mPresContext; - mUnconstrainedWidth = aState.mUnconstrainedWidth; - mUnconstrainedHeight = aState.mUnconstrainedHeight; - mMaxElementSizePointer = aState.mMaxElementSizePointer; - - mAscents = mAscentBuf; - mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]); -} - -nsLineLayout::~nsLineLayout() -{ - NS_IF_RELEASE(mBlockContent); - if (mAscents != mAscentBuf) { - delete [] mAscents; - } -} - -nsresult -nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - SetReflowSpace(aState.mCurrentBand.availSpace); - - mState.mSkipLeadingWhiteSpace = PR_TRUE; - mState.mColumn = 0; - - mState.mKidFrame = nsnull; - mState.mPrevKidFrame = nsnull; - mState.mKidIndex = aLine->mFirstContentOffset; - mState.mKidFrameNum = 0; - mState.mMaxElementSize.width = 0; - mState.mMaxElementSize.height = 0; - mState.mMaxAscent = nsnull; - mState.mMaxDescent = nsnull; - - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - mPendingBreak = NS_STYLE_CLEAR_NONE; - - mLine = aLine; - mKidPrevInFlow = nsnull; - mNewFrames = 0; - mFramesReflowed = 0; - - mMarginApplied = PR_FALSE; - - mMustReflowMappedChildren = PR_FALSE; - mY = aState.mY; - mMaxHeight = aState.mAvailSize.height; - mReflowDataChanged = PR_FALSE; - - mLineHeight = 0; - - mNoWrap = PR_FALSE; - const nsStyleText* styleText; - mBlock->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)styleText); - switch (styleText->mWhiteSpace) { - case NS_STYLE_WHITESPACE_PRE: - case NS_STYLE_WHITESPACE_NOWRAP: - mNoWrap = PR_TRUE; - break; - } - - return rv; -} - -void -nsLineLayout::SetReflowSpace(nsRect& aAvailableSpaceRect) -{ - nscoord x0 = aAvailableSpaceRect.x; - mLeftEdge = x0; - mState.mX = x0; - mRightEdge = x0 + aAvailableSpaceRect.width; - - mMaxWidth = mRightEdge - x0; - mReflowDataChanged = PR_TRUE; - mMustReflowMappedChildren = PR_TRUE; -} - -nsresult -nsLineLayout::SetAscent(nscoord aAscent) -{ - PRInt32 kidFrameNum = mState.mKidFrameNum; - if (kidFrameNum == mMaxAscents) { - mMaxAscents *= 2; - nscoord* newAscents = new nscoord[mMaxAscents]; - if (nsnull != newAscents) { - nsCRT::memcpy(newAscents, mAscents, sizeof(nscoord) * kidFrameNum); - if (mAscents != mAscentBuf) { - delete [] mAscents; - } - mAscents = newAscents; - } else { - return NS_ERROR_OUT_OF_MEMORY; - } - } - mAscents[kidFrameNum] = aAscent; - return NS_OK; -} - -void -nsLineLayout::AtSpace() -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtSpace: kidFrame=%p kidIndex=%d mX=%d", - mState.mKidFrame, mState.mKidIndex, mState.mX)); - mBreakFrame = nsnull; - mSavedState.mKidFrame = nsnull; -} - -void -nsLineLayout::AtWordStart(nsIFrame* aFrame, nscoord aX) -{ - if (nsnull == mBreakFrame) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtWordStart: aFrame=%p kidFrame=%p[%d] aX=%d mX=%d", - aFrame, - mState.mKidFrame, mState.mKidIndex, - aX, mState.mX)); - - mSavedState = mState; - mBreakFrame = aFrame; - mBreakX = aX; - } - else if (mBreakFrame == aFrame) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtWordStart: update aX=%d", aX)); - NS_ASSERTION((mSavedState.mKidFrame == mState.mKidFrame) && - (mSavedState.mKidIndex == mState.mKidIndex) && - (mSavedState.mKidFrameNum == mState.mKidFrameNum), - "bad break state"); - mBreakX = aX; - } -} - -PRBool -nsLineLayout::CanBreak() -{ - if (nsnull == mBreakFrame) { - // There is no word to break at - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: no break frame")); - return PR_FALSE; - } - - if (mSavedState.mKidFrame == mLine->mFirstChild) { - // The line's first frame contains the break position; we are not - // allowed to break if the break would empty the line. - if (0 == mBreakX) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: breakX=0")); - return PR_FALSE; - } - } - - // Compute the break x coordinate in our coordinate system by adding - // in the X coordinates of each of the frames between the break - // frame and the containing block frame. - nscoord breakX = mBreakX; - nsIFrame* frame = mBreakFrame; - for (;;) { - nsRect r; - frame->GetRect(r); - breakX += r.x; - nsIFrame* parent; - frame->GetGeometricParent(parent); - if (parent == mBlock) { - break; - } - frame = parent; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: backup from=%p[%d]/%d to=%p[%d]/%d breakX=%d", - mState.mKidFrame, mState.mKidIndex, mState.mKidFrameNum, - mSavedState.mKidFrame, mSavedState.mKidIndex, mSavedState.mKidFrameNum, - breakX)); - - // Revert the line layout back to where it was when the break point - // was found. - mState = mSavedState; - - // Change the right edge to the breakX so that when we reflow the - // child it will stop just before the break point. - mRightEdge = breakX; - - // Forgot word break - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - - return PR_TRUE; -} - -/** - * Attempt to avoid reflowing a child by seeing if it's been touched - * since the last time it was reflowed. - */ -nsresult -nsLineLayout::ReflowMappedChild() -{ - nsIFrame* kidFrame = mState.mKidFrame; - - if (mMustReflowMappedChildren || PR_TRUE) { -/* - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: must reflow frame=%p[%d]", - kidFrame, mKidIndex)); -*/ - return ReflowChild(nsnull, PR_FALSE); - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: attempt frame=%p[%d]", - kidFrame, mState.mKidIndex)); - - // If the child is a container then we need to reflow it if there is - // a change in width. Note that if it's an empty container then it - // doesn't really matter how much space we give it. - if (mBlockReflowState.mDeltaWidth != 0) { - nsIFrame* f; - kidFrame->FirstChild(f); - if (nsnull != f) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: has children")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // If we need the max-element size and we are splittable then we - // have to reflow to get it. - nsSplittableType splits; - kidFrame->IsSplittable(splits); -#if 0 - if (nsnull != mMaxElementSizePointer) { - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: need max-element-size")); - return ReflowChild(nsnull, PR_FALSE); - } - } -#else - // XXX For now, if the child is splittable we reflow it. The reason - // is that the text whitespace compression needs to be consulted - // here to properly handle reflow avoidance. To do that properly we - // really need a first-rate protocol here (WillPlace? - // CanAvoidReflow?) that gets the frame involved. - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: splittable hack")); - return ReflowChild(nsnull, PR_FALSE); - } -#endif - - nsFrameState state; - kidFrame->GetFrameState(state); - - // XXX a better term for this is "dirty" and once we add a dirty - // bit that's what we'll do here. - - // XXX this check will cause pass2 of table reflow to reflow - // everything; tables will be even faster if we have a dirty bit - // instead (that way we can avoid reflowing non-splittables on - // pass2) - if (0 != (state & NS_FRAME_IN_REFLOW)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: frame is dirty")); - return ReflowChild(nsnull, PR_FALSE); - } - - if (NS_FRAME_IS_SPLITTABLE(splits)) { - // XXX a next-in-flow propogated dirty-bit eliminates this code - - // The splittable frame has not yet been reflowed. This means - // that, in theory, its state is well defined. However, if it has - // a prev-in-flow and that frame has been touched then we need to - // reflow this frame. - nsIFrame* prevInFlow; - kidFrame->GetPrevInFlow(prevInFlow); - if (nsnull != prevInFlow) { - nsFrameState prevState; - prevInFlow->GetFrameState(prevState); - if (0 != (prevState & NS_FRAME_IN_REFLOW)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: prev-in-flow frame is dirty")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // If the child has a next-in-flow then never-mind, we need to - // reflow it in case it has more/less space to reflow into. - nsIFrame* nextInFlow; - kidFrame->GetNextInFlow(nextInFlow); - if (nsnull != nextInFlow) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: frame has next-in-flow")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // Success! We have (so far) avoided reflowing the child. However, - // we do need to place it and advance our position state. Get the - // size of the child and its reflow metrics for placing. - nsIStyleContextPtr kidSC; - nsresult rv = kidFrame->GetStyleContext(mPresContext, kidSC.AssignRef()); - if (NS_OK != rv) { - return rv; - } - const nsStyleDisplay* kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_FLOAT_NONE != kidDisplay->mFloats) { - // XXX If it floats it needs to go through the normal path so that - // PlaceFloater is invoked. - return ReflowChild(nsnull, PR_FALSE); - } - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); - PRBool isBlock = PR_FALSE; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - if (kidFrame != mLine->mFirstChild) { - // Block items must be at the start of a line, therefore we need - // to break before the block item. - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: block requires break-before")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - isBlock = PR_TRUE; - break; - } - - // Compute new total width of child using its current margin values - // (they may have changed since the last time the child was reflowed) - nsRect kidRect; - kidFrame->GetRect(kidRect); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - nscoord totalWidth; - totalWidth = kidMargin.left + kidMargin.right + kidRect.width; - - // If the child intersects the area affected by the reflow then - // we need to reflow it. - nscoord x = mState.mX; - if (x + kidMargin.left + kidRect.width > mRightEdge) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: failed edge test")); - // XXX if !splittable then return NS_LINE_LAYOUT_BREAK_BEFORE - return ReflowChild(nsnull, PR_FALSE); - } - - // Make sure the child will fit. The child always fits if it's the - // first child on the line. - nscoord availWidth = mRightEdge - x; - if (mUnconstrainedWidth || - (kidFrame == mLine->mFirstChild) || - (totalWidth <= availWidth)) { - // By convention, mReflowResult is set during ResizeReflow, - // IncrementalReflow AND GetReflowMetrics by those frames that are - // line layout aware. - mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; - nsReflowMetrics kidMetrics(nsnull); - kidFrame->GetReflowMetrics(mPresContext, kidMetrics); - - nsSize maxElementSize; - nsSize* kidMaxElementSize = nsnull; - if (nsnull != mMaxElementSizePointer) { - kidMaxElementSize = &maxElementSize; - maxElementSize.width = kidRect.width; - maxElementSize.height = kidRect.height; - } - kidRect.x = x + kidMargin.left; - kidRect.y = mY; - - if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) { - mState.mSkipLeadingWhiteSpace = PR_FALSE; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: fit size=%d,%d", - kidRect.width, kidRect.height)); - mLine->mIsBlock = isBlock; - return PlaceChild(kidRect, kidMetrics, kidMaxElementSize, kidMargin, - NS_FRAME_COMPLETE); - } - - // The child doesn't fit as is; if it's splittable then reflow it - // otherwise return break-before status so that the non-splittable - // child is pushed to the next line. - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: can't directly fit")); - return ReflowChild(nsnull, PR_FALSE); - } - return NS_LINE_LAYOUT_BREAK_BEFORE; -} - -// Return values: <0 for error -// 0 == NS_LINE_LAYOUT -nsresult -nsLineLayout::ReflowChild(nsIReflowCommand* aReflowCommand, - PRBool aNewChild) -{ - nsIFrame* kidFrame = mState.mKidFrame; - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: attempt frame=%p[%d] mX=%d availWidth=%d", - kidFrame, mState.mKidIndex, - mState.mX, mRightEdge - mState.mX)); - - // Get kid frame's style context - nsIStyleContextPtr kidSC; - nsresult rv = kidFrame->GetStyleContext(mPresContext, kidSC.AssignRef()); - if (NS_OK != rv) { - return rv; - } - - // See if frame belongs in the line. - // XXX absolute positioning - // XXX floating frames - // XXX break-before - const nsStyleDisplay * kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - PRBool isBlock = PR_FALSE; - PRBool isFirstChild = PRBool(kidFrame == mLine->mFirstChild); - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_NONE: - // Make sure the frame remains zero sized. - kidFrame->WillReflow(*mPresContext); - kidFrame->SetRect(nsRect(mState.mX, mY, 0, 0)); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: display=none")); - return NS_LINE_LAYOUT_COMPLETE; - - case NS_STYLE_DISPLAY_INLINE: - break; - - default: - isBlock = PR_TRUE; - if (!isFirstChild) { - // XXX Make sure child is dirty for next time - kidFrame->WillReflow(*mPresContext); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: block requires break-before")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - break; - } - - // Get the available size to reflow the child into - PRBool didBreak = PR_FALSE; - reflow_it_again_sam: - nscoord availWidth = mRightEdge - mState.mX; - nsSize kidAvailSize; - kidAvailSize.width = availWidth; - kidAvailSize.height = mMaxHeight; - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - if (!mUnconstrainedWidth) { - if (mNoWrap) { - // When our reflow is constrained and we are we are not supposed - // to wrap make sure the child will fit regardless of how much - // space is left. - if (isBlock) { - // Never give a block an infinite width - kidAvailSize.width = mRightEdge - mLeftEdge; - } - else { - kidAvailSize.width = NS_UNCONSTRAINEDSIZE; - } - } - else { - kidAvailSize.width -= kidMargin.left + kidMargin.right; - if (!isFirstChild && (kidAvailSize.width <= 0)) { - // No room. - if (!didBreak && CanBreak()) { - kidFrame = mState.mKidFrame; - didBreak = PR_TRUE; - mPendingBreak = NS_STYLE_CLEAR_NONE; - goto reflow_it_again_sam; - } - - // XXX Make sure child is dirty for next time - kidFrame->WillReflow(*mPresContext); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: !fit")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - } - } - - // Reflow the child - mFramesReflowed++; - nsRect kidRect; - nsSize maxElementSize; - nsSize* kidMaxElementSize = nsnull; - nsReflowStatus kidReflowStatus; - if (nsnull != mMaxElementSizePointer) { - kidMaxElementSize = &maxElementSize; - } - nsReflowMetrics kidMetrics(kidMaxElementSize); - - // Get reflow reason set correctly. It's possible that we created a - // child and then decided that we cannot reflow it (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 kidReason = eReflowReason_Resize; - if (nsnull != aReflowCommand) { - kidReason = eReflowReason_Incremental; - } - else if (aNewChild) { - kidReason = eReflowReason_Initial; - } - else { - nsFrameState state; - kidFrame->GetFrameState(state); - if (NS_FRAME_FIRST_REFLOW & state) { - kidReason = eReflowReason_Initial; - } - } - - nsReflowState kidReflowState(kidFrame, *mBlockReflowState.reflowState, - kidAvailSize, kidReason); - kidReflowState.reflowCommand = aReflowCommand; - mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; - nscoord dx = mState.mX + kidMargin.left; - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: reflowing frame into %d,%d", - kidAvailSize.width, kidAvailSize.height)); - if (isBlock) { - // Calculate top margin by collapsing with previous bottom margin - nscoord negTopMargin; - nscoord posTopMargin; - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - if (kidMargin.top < 0) { - negTopMargin = -kidMargin.top; - posTopMargin = 0; - } else { - negTopMargin = 0; - posTopMargin = kidMargin.top; - } - - // XXX if (nav4_compatability) - // Calculate the previous margin's positive and negative value. - // If the current top margin is not defined by css then just use - // what is cached in the block reflow state. Otherwise if the top - // margin is defined by css then wipe out any synthetic margin. - nscoord prevPos = mBlockReflowState.mPrevPosBottomMargin; - nscoord prevNeg = mBlockReflowState.mPrevNegBottomMargin; - if (eStyleUnit_Null != kidSpacing->mMargin.GetTopUnit()) { - if (mBlockReflowState.mPrevMarginSynthetic) { - prevPos = 0; - prevNeg = 0; - } - } - else { - // When our top margin is not specified by css...act like - // ebina's engine. - if ((nsnull != mLine->mPrevLine) && !mLine->mPrevLine->mIsBlock) { - // Supply a default top margin - const nsStyleFont* styleFont; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)styleFont); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(styleFont->mFont); - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = fm->GetHeight(); - mBlockReflowState.mPrevMarginSynthetic = PR_TRUE; - NS_RELEASE(fm); - } - } - - nscoord maxPos = PR_MAX(prevPos, posTopMargin); - nscoord maxNeg = PR_MAX(prevNeg, negTopMargin); - nscoord topMargin = maxPos - maxNeg; - - // This is no longer a break point - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - - mY += topMargin; - mBlockReflowState.mY += topMargin; - // XXX tell block what topMargin ended up being so that it can - // undo it if it ends up pushing the line. - - NS_ASSERTION(0 == mPendingBreak, "whoops: uncleared break"); - mSpaceManager->Translate(dx, mY); - kidFrame->WillReflow(*mPresContext); - kidFrame->MoveTo(dx, mY); - rv = mBlock->ReflowBlockChild(kidFrame, mPresContext, - mSpaceManager, kidMetrics, kidReflowState, - kidRect, kidReflowStatus); - mSpaceManager->Translate(-dx, -mY); - - if ((0 == kidRect.width) && (0 == kidRect.height)) { - // When a block child collapses into nothingness we don't apply - // it's margins. - mY -= topMargin; - mBlockReflowState.mY -= topMargin; - } - else { - // XXX if (nav4_compatability) - // If the block frame we just reflowed has no bottom margin as - // specified by css, then we supply our own. - if (eStyleUnit_Null == kidSpacing->mMargin.GetBottomUnit()) { - // ebina's engine uses the height of the font for the bottom margin. - nsIStyleContext* blockSC; - const nsStyleFont* styleFont; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)styleFont); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(styleFont->mFont); - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = fm->GetHeight(); - mBlockReflowState.mPrevMarginSynthetic = PR_TRUE; - NS_RELEASE(fm); - } - else { - // Save away bottom margin information for later - if (kidMargin.bottom < 0) { - mBlockReflowState.mPrevNegBottomMargin = -kidMargin.bottom; - mBlockReflowState.mPrevPosBottomMargin = 0; - } else { - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = kidMargin.bottom; - } - mBlockReflowState.mPrevMarginSynthetic = PR_FALSE; - } - } - - kidRect.x = dx; - kidRect.y = mY; - kidMetrics.width = kidRect.width; - kidMetrics.height = kidRect.height; - kidMetrics.ascent = kidRect.height; - kidMetrics.descent = 0; - } - else { - // Apply bottom margin speculatively before reflowing the child - nscoord bottomMargin = mBlockReflowState.mPrevPosBottomMargin - - mBlockReflowState.mPrevNegBottomMargin; - if (!mMarginApplied) { - // Before we place the first inline child on this line apply - // the previous block's bottom margin. - mY += bottomMargin; - mBlockReflowState.mY += bottomMargin; - } - - NS_ASSERTION(0 == mPendingBreak, "whoops: uncleared break"); - kidFrame->WillReflow(*mPresContext); - kidFrame->MoveTo(dx, mY); - rv = mBlock->ReflowInlineChild(*this, kidFrame, kidMetrics, - kidReflowState, kidReflowStatus); - - // See if speculative application of the margin should stick - if (!mMarginApplied) { - if (0 == kidMetrics.height) { - // No, undo margin application when we get a zero height child. - mY -= bottomMargin; - mBlockReflowState.mY -= bottomMargin; - } - else { - // Yes, keep the margin application. - mMarginApplied = PR_TRUE; - mBlockReflowState.mPrevPosBottomMargin = 0; - mBlockReflowState.mPrevNegBottomMargin = 0; - // XXX tell block what bottomMargin ended up being so that it can - // undo it if it ends up pushing the line. - } - } - - kidRect.x = dx; - kidRect.y = mY; - kidRect.width = kidMetrics.width; - kidRect.height = kidMetrics.height; - } - if (NS_OK != rv) return rv; - - // See if the child fit - if (kidMetrics.width > kidAvailSize.width) { - if (!isFirstChild) { - if (!didBreak && CanBreak()) { - kidFrame = mState.mKidFrame; - didBreak = PR_TRUE; - mPendingBreak = NS_STYLE_CLEAR_NONE; - goto reflow_it_again_sam; - } - else { - // We are out of room. - // XXX mKidPrevInFlow - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: !fit size=%d,%d", - kidRect.width, kidRect.height)); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - } - } - - // Non-aware children that take up space act like words; which means - // that space immediately following them must not be skipped over. - if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) { - if ((kidRect.width != 0) && (kidRect.height != 0)) { - mState.mSkipLeadingWhiteSpace = PR_FALSE; - } - } - - // Now place the child - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: fit size=%d,%d", - kidRect.width, kidRect.height)); - mLine->mIsBlock = isBlock; - return PlaceChild(kidRect, kidMetrics, kidMaxElementSize, - kidMargin, kidReflowStatus); -} - -nsresult -nsLineLayout::PlaceChild(nsRect& kidRect, - const nsReflowMetrics& kidMetrics, - const nsSize* kidMaxElementSize, - const nsMargin& kidMargin, - nsReflowStatus kidReflowStatus) -{ - nscoord horizontalMargins = 0; - - // Special case to position outside list bullets. - // XXX RTL bullets - PRBool isBullet = PR_FALSE; - if (mBlockReflowState.mListPositionOutside) { - PRBool isFirstChild = PRBool(mState.mKidFrame == mLine->mFirstChild); - PRBool isFirstLine = PRBool(nsnull == mLine->mPrevLine); - if (isFirstChild && isFirstLine) { - nsIFrame* blockPrevInFlow; - mBlock->GetPrevInFlow(blockPrevInFlow); - PRBool isFirstInFlow = PRBool(nsnull == blockPrevInFlow); - if (isFirstInFlow) { - isBullet = PR_TRUE; - // We are placing the first child of the block therefore this - // is the bullet that is being reflowed. The bullet is placed - // in the padding area of this block. Don't worry about - // getting the Y coordinate of the bullet right (vertical - // alignment will take care of that). - - // Compute gap between bullet and inner rect left edge - const nsStyleFont* font; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(font->mFont); - nscoord kidAscent = fm->GetMaxAscent(); - nscoord dx = fm->GetHeight() / 2; // from old layout engine - NS_RELEASE(fm); - - // XXX RTL bullets - kidRect.x = mState.mX - kidRect.width - dx; - mState.mKidFrame->SetRect(kidRect); - } - } - } - if (!isBullet) { - // Place normal in-flow child - mState.mKidFrame->SetRect(kidRect); - - // Advance - // XXX RTL - horizontalMargins = kidMargin.left + kidMargin.right; - nscoord totalWidth = kidMetrics.width + horizontalMargins; - mState.mX += totalWidth; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::PlaceChild: frame=%p[%d] {%d, %d, %d, %d}", - mState.mKidFrame, - mState.mKidIndex, - kidRect.x, kidRect.y, kidRect.width, kidRect.height)); - - if (nsnull != mMaxElementSizePointer) { - // XXX I'm not certain that this is doing the right thing; rethink this - nscoord elementWidth = kidMaxElementSize->width + horizontalMargins; - if (elementWidth > mState.mMaxElementSize.width) { - mState.mMaxElementSize.width = elementWidth; - } - if (kidMetrics.height > mState.mMaxElementSize.height) { - mState.mMaxElementSize.height = kidMetrics.height; - } - } - if (kidMetrics.ascent > mState.mMaxAscent) { - mState.mMaxAscent = kidMetrics.ascent; - } - if (kidMetrics.descent > mState.mMaxDescent) { - mState.mMaxDescent = kidMetrics.descent; - } - SetAscent(mLine->mIsBlock ? 0 : kidMetrics.ascent); - - // Set completion status - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - mLine->mLastContentOffset = mState.mKidIndex; - if (NS_FRAME_IS_COMPLETE(kidReflowStatus)) { - mLine->mLastContentIsComplete = PR_TRUE; - if (mLine->mIsBlock || - (NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER == mReflowResult) || - (NS_STYLE_CLEAR_NONE != mPendingBreak)) { - rv = NS_LINE_LAYOUT_BREAK_AFTER; - if (NS_STYLE_CLEAR_LINE == mPendingBreak) { - mPendingBreak = NS_STYLE_CLEAR_NONE; - } - } - mKidPrevInFlow = nsnull; - } - else { - mLine->mLastContentIsComplete = PR_FALSE; - rv = NS_LINE_LAYOUT_NOT_COMPLETE; - mKidPrevInFlow = mState.mKidFrame; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::PlaceChild: rv=%d", rv)); - return rv; -} - -nsresult -nsLineLayout::IncrementalReflowFromChild(nsIReflowCommand* aReflowCommand, - nsIFrame* aChildFrame) -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - - mLine->mBounds.x = mState.mX; - mLine->mBounds.y = mY; - mState.mKidFrame = mLine->mFirstChild; - mState.mKidFrameNum = 0; - while (mState.mKidFrameNum < mLine->mChildCount) { - nsresult childReflowStatus; - if (mState.mKidFrame == aChildFrame) { - childReflowStatus = ReflowChild(aReflowCommand, PR_FALSE); - } else { - childReflowStatus = ReflowMappedChild(); - } - - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - -done: - // Perform alignment operations - AlignChildren(); - - // Set final bounds of the line - mLine->mBounds.height = mLineHeight; - mLine->mBounds.width = mState.mX - mLine->mBounds.x; - - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowMapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::SplitLine(PRInt32 aChildReflowStatus) -{ - PRInt32 pushCount = mLine->mChildCount - mState.mKidFrameNum; - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - - if (NS_LINE_LAYOUT_NOT_COMPLETE == aChildReflowStatus) { - // When a line is not complete it indicates that the last child on - // the line reflowed and took some space but wasn't given enough - // space to complete. Sometimes when this happens we will need to - // create a next-in-flow for the child. - nsIFrame* nextInFlow; - mState.mPrevKidFrame->GetNextInFlow(nextInFlow); - if (nsnull == nextInFlow) { - // Create a continuation frame for the child frame and insert it - // into our lines child list. - nsIFrame* nextFrame; - mState.mPrevKidFrame->GetNextSibling(nextFrame); - nsIStyleContext* kidSC; - mState.mPrevKidFrame->GetStyleContext(mPresContext, kidSC); - mState.mPrevKidFrame->CreateContinuingFrame(mPresContext, mBlock, kidSC, - nextInFlow); - NS_RELEASE(kidSC); - if (nsnull == nextInFlow) { - return NS_ERROR_OUT_OF_MEMORY; - } - mState.mPrevKidFrame->SetNextSibling(nextInFlow); - nextInFlow->SetNextSibling(nextFrame); - mNewFrames++; - - // Add new child to our line - mLine->mChildCount++; - - // Set mKidFrame to the new next-in-flow so that we will - // push it when we push children. Increment the number of - // remaining kids now that there is one more. - mState.mKidFrame = nextInFlow; - pushCount++; - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::SplitLine: created next in flow %p", - nextInFlow)); - } - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::SplitLine: pushing %d frames", - pushCount)); - - if (0 != pushCount) { - NS_ASSERTION(nsnull != mState.mKidFrame, "whoops"); - nsLineData* from = mLine; - nsLineData* to = mLine->mNextLine; - if (nsnull != to) { - // Only push into the next line if it's empty; otherwise we can - // end up pushing a frame which is continued into the same frame - // as it's continuation. This causes all sorts of side effects - // so we don't allow it. - if (to->mChildCount != 0) { - nsLineData* insertedLine = new nsLineData(); - from->mNextLine = insertedLine; - to->mPrevLine = insertedLine; - insertedLine->mPrevLine = from; - insertedLine->mNextLine = to; - to = insertedLine; - to->mLastContentOffset = from->mLastContentOffset; - to->mLastContentIsComplete = from->mLastContentIsComplete; - } - } else { - to = new nsLineData(); - to->mPrevLine = from; - from->mNextLine = to; - } - if (nsnull == to) { - return NS_ERROR_OUT_OF_MEMORY; - } - - PRInt32 kidIndexInParent; - mState.mKidFrame->GetContentIndex(kidIndexInParent); - to->mFirstChild = mState.mKidFrame; - to->mChildCount += pushCount; - to->mFirstContentOffset = kidIndexInParent; - - // The to-line is going to be reflowed therefore it's last content - // offset and completion status don't matter. In fact, it's expensive - // to compute them so don't bother. -#ifdef NS_DEBUG - to->mLastContentOffset = -1; - to->mLastContentIsComplete = PRPackedBool(0x255); -#endif - - from->mChildCount -= pushCount; - NS_ASSERTION(0 != from->mChildCount, "bad push"); -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - from->Verify(); - } -#endif -#ifdef NOISY_REFLOW - printf("After push, from-line (%d):\n", pushCount); - from->List(stdout, 1); - printf("After push, to-line:\n"); - to->List(stdout, 1); -#endif - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsLineLayout::SplitLine: returning %d", - aChildReflowStatus)); - return aChildReflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::ReflowMapped() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - - mState.mKidFrame = mLine->mFirstChild; - mState.mKidFrameNum = 0; - while (mState.mKidFrameNum < mLine->mChildCount) { - nsresult childReflowStatus = ReflowMappedChild(); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowMapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -static PRBool -IsBlock(const nsStyleDisplay* aDisplay) -{ - switch (aDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - return PR_TRUE; - } - return PR_FALSE; -} - -// XXX fix this code to look at the available width and if it's too -// small for the next child then skip the pullup (and return -// BREAK_AFTER status). - -nsresult -nsLineLayout::PullUpChildren() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - nsIFrame* prevKidFrame = mState.mPrevKidFrame; - - nsBlockFrame* currentBlock = mBlock; - nsLineData* line = mLine->mNextLine; - while (nsnull != currentBlock) { - - // Pull children from the next line - while (nsnull != line) { - // Get first child from next line - mState.mKidFrame = line->mFirstChild; - if (nsnull == mState.mKidFrame) { - NS_ASSERTION(0 == line->mChildCount, "bad line list"); - nsLineData* nextLine = line->mNextLine; - nsLineData* prevLine = line->mPrevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - delete line;/* XXX free-list in block-reflow-state? */ - line = nextLine; - continue; - } - - // XXX Avoid the pullup work if the child cannot already fit - // (e.g. it's not splittable and can't fit) - - // XXX change this to use the next-line's mIsBlock when possible - // (make sure push code set it's properly for this to work: only - // from reflow-unmapped) - - // If the child is a block element then if this is not the first - // line in the block or if it's the first line and it's not the - // first child in the line then we cannot pull-up the child. - nsresult rv; - const nsStyleDisplay* kidDisplay; - rv = mState.mKidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if (NS_OK != rv) { - return rv; - } - if (IsBlock(kidDisplay)) { - if ((nsnull != mLine->mPrevLine) || (0 != mLine->mChildCount)) { - goto done; - } - } - - // Make pulled child part of this line - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsLineLayout::PullUpChildren: trying to pull frame=%p", - mState.mKidFrame)); - mLine->mChildCount++; - if (0 == --line->mChildCount) { - // Remove empty lines from the list - nsLineData* nextLine = line->mNextLine; - nsLineData* prevLine = line->mPrevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - delete line;/* XXX free-list in block-reflow-state? */ - line = nextLine; - } - else { - // Repair the first content offset of the line. The first - // child of the line's index-in-parent should be the line's - // new first content offset. - mState.mKidFrame->GetNextSibling(line->mFirstChild); - PRInt32 indexInParent; - line->mFirstChild->GetContentIndex(indexInParent); - line->mFirstContentOffset = indexInParent; -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - line->Verify(); - } -#endif - } - - // Try to reflow it like any other mapped child - nsresult childReflowStatus = ReflowMappedChild(); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - - // Grab the block's next in flow - nsIFrame* nextInFlow; - currentBlock->GetNextInFlow(nextInFlow); - currentBlock = (nsBlockFrame*)nextInFlow; - if (nsnull != currentBlock) { - line = currentBlock->GetFirstLine(); - } - } - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from PullUpChildren"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::CreateFrameFor(nsIContent* aKid) -{ - nsIStyleContextPtr kidSC = - mPresContext->ResolveStyleContextFor(aKid, mBlock); // XXX bad API - if (nsnull == kidSC) { - return NS_ERROR_OUT_OF_MEMORY; - } - const nsStylePosition* kidPosition = (const nsStylePosition*) - kidSC->GetStyleData(eStyleStruct_Position); - const nsStyleDisplay* kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - - // Check whether it wants to floated or absolutely positioned - PRBool isBlock = PR_FALSE; - nsIFrame* kidFrame; - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == kidPosition->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if (NS_STYLE_FLOAT_NONE != kidDisplay->mFloats) { - rv = nsPlaceholderFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if ((NS_STYLE_OVERFLOW_SCROLL == kidDisplay->mOverflow) || - (NS_STYLE_OVERFLOW_AUTO == kidDisplay->mOverflow)) { - rv = NS_NewScrollFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if (nsnull == mKidPrevInFlow) { - // Create initial frame for the child - nsIContentDelegate* kidDel; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_NONE: - rv = nsFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - break; - - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - isBlock = PR_TRUE; - // FALL THROUGH - default: - kidDel = aKid->GetDelegate(mPresContext); - rv = kidDel->CreateFrame(mPresContext, aKid, mBlock, kidSC, kidFrame); - NS_RELEASE(kidDel); - break; - } - } else { - // Since kid has a prev-in-flow, use that to create the next - // frame. - rv = mKidPrevInFlow->CreateContinuingFrame(mPresContext, mBlock, kidSC, - kidFrame); - NS_ASSERTION(0 == mLine->mChildCount, "bad continuation"); - } - if (NS_OK != rv) { - return rv; - } - if (NS_OK == rv) { - // Wrap the frame in a view if necessary - rv = nsHTMLBase::CreateViewForFrame(mPresContext, kidFrame, kidSC, - PR_FALSE); - if (NS_OK != rv) { - return rv; - } - } - - mState.mKidFrame = kidFrame; - mNewFrames++; - - if (isBlock && (0 != mLine->mChildCount)) { - // When we are not at the start of a line we need to break - // before a block element. - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - - return rv; -} - -nsresult -nsLineLayout::ReflowUnmapped() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - for (;;) { - nsIContentPtr kid = mBlockContent->ChildAt(mState.mKidIndex); - if (kid.IsNull()) { - break; - } - - // Create a frame for the new content - nsresult rv = CreateFrameFor(kid); - if (rv < 0) { - reflowStatus = rv; - goto done; - } - - // Add frame to our list - if (nsnull != mState.mPrevKidFrame) { - mState.mPrevKidFrame->SetNextSibling(mState.mKidFrame); - } - if (0 == mLine->mChildCount) { - mLine->mFirstChild = mState.mKidFrame; - mBlock->SetFirstChild(mState.mKidFrame); - } - mLine->mChildCount++; - - nsresult childReflowStatus; - if (rv == NS_LINE_LAYOUT_BREAK_BEFORE) { - // If we break before a frame is even supposed to layout then we - // need to split the line. - childReflowStatus = rv; - - // XXX Mark new frame dirty so it gets reflow later on - mState.mKidFrame->WillReflow(*mPresContext); - goto split_line; - } - - // Reflow new child frame - childReflowStatus = ReflowChild(nsnull, PR_TRUE); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - mState.mKidIndex++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - mState.mKidIndex++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - NS_ASSERTION(nsnull == mLine->mNextLine, "bad line list"); - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowUnmapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::ReflowLine() -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("enter nsLineLayout::ReflowLine: childCount=%d {%d, %d, %d, %d}", - mLine->mChildCount, - mLine->mBounds.x, mLine->mBounds.y, - mLine->mBounds.width, mLine->mBounds.height)); - - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - - mLine->mBounds.x = mState.mX; - mLine->mBounds.y = mY; - mOldChildCount = mLine->mChildCount; - - // Reflow the mapped frames - if (0 != mLine->mChildCount) { - rv = ReflowMapped(); - if (rv < 0) return rv; - } - - // Pull-up any frames from the next line - if (NS_LINE_LAYOUT_COMPLETE == rv) { - if (nsnull != mLine->mNextLine) { - rv = PullUpChildren(); - if (rv < 0) return rv; - } - - // Try reflowing any unmapped children - if (NS_LINE_LAYOUT_COMPLETE == rv) { - if (nsnull == mLine->mNextLine) { - rv = ReflowUnmapped(); - if (rv < 0) return rv; - } - } - } - - // Perform alignment operations - AlignChildren(); - - // Set final bounds of the line - mLine->mBounds.height = mLineHeight; - mLine->mBounds.width = mState.mX - mLine->mBounds.x; - -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - mLine->Verify(); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("exit nsLineLayout::ReflowLine: childCount=%d {%d, %d, %d, %d}", - mLine->mChildCount, - mLine->mBounds.x, mLine->mBounds.y, - mLine->mBounds.width, mLine->mBounds.height)); - return rv; -} - -void -nsLineLayout::AlignChildren() -{ - NS_PRECONDITION(mLine->mChildCount == mState.mKidFrameNum, "bad line reflow"); - - // Block lines don't require (or allow!) alignment - if (mLine->mIsBlock) { - mLineHeight = mState.mMaxAscent + mState.mMaxDescent; - } - else { - // Avoid alignment when we didn't actually reflow any frames and we - // also didn't change the number of frames we had (which means the - // pullup code didn't pull anything up). When this happens it means - // that nothing changed which means that we can avoid the alignment - // work. - if ((0 == mFramesReflowed) && (mOldChildCount == mLine->mChildCount)) { - mLineHeight = mLine->mBounds.height; - } - } - - nsIStyleContextPtr blockSC; - mBlock->GetStyleContext(mPresContext, blockSC.AssignRef()); - const nsStyleFont* blockFont = (const nsStyleFont*) - blockSC->GetStyleData(eStyleStruct_Font); - const nsStyleText* blockText = (const nsStyleText*) - blockSC->GetStyleData(eStyleStruct_Text); - const nsStyleDisplay* blockDisplay = (const nsStyleDisplay*) - blockSC->GetStyleData(eStyleStruct_Display); - - // First vertically align the children on the line; this will - // compute the actual line height for us. - if (!mLine->mIsBlock) { - mLineHeight = - nsCSSLayout::VerticallyAlignChildren(mPresContext, mBlock, blockFont, - mY, - mLine->mFirstChild, - mLine->mChildCount, - mAscents, mState.mMaxAscent); - } - - // Now horizontally place the children - nsCSSLayout::HorizontallyPlaceChildren(mPresContext, mBlock, - blockText->mTextAlign, - blockDisplay->mDirection, - mLine->mFirstChild, - mLine->mChildCount, - mState.mX - mLeftEdge, - mMaxWidth); - - // Last, apply relative positioning - nsCSSLayout::RelativePositionChildren(mPresContext, mBlock, - mLine->mFirstChild, - mLine->mChildCount); -} diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h deleted file mode 100644 index 34bc57051e2..00000000000 --- a/mozilla/layout/generic/nsLineLayout.h +++ /dev/null @@ -1,248 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#ifndef nsLineLayout_h___ -#define nsLineLayout_h___ - -#include "nsIFrame.h" -#include "nsCoord.h" -#include "nsSize.h" -#include "nsVoidArray.h" - -class nsIPresContext; -class nsISpaceManager; -class nsBlockFrame; -struct nsBlockReflowState; -struct nsLineLayout; - -/* d76e29b0-ff56-11d1-89e7-006008911b81 */ -#define NS_IINLINE_FRAME_IID \ -{0xd76e29b0, 0xff56, 0x11d1, {0x89, 0xe7, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} - -/** - * Interface to "inline frames". Inline frames are those that are aware - * of html line layout. - * - * Note that this interface does not expose AddRef/Release (like all frame - * interfaces) - */ -class nsIInlineFrame : private nsISupports { -public: - NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0; - - NS_IMETHOD ReflowInline(nsLineLayout& aLineLayout, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) = 0; -}; - -//---------------------------------------------------------------------- - -/** - * Persistent per-line data - */ -struct nsLineData { - nsLineData(); - ~nsLineData(); - - nsIFrame* GetLastChild(); - nsresult Verify(PRBool aFinalCheck = PR_TRUE) const; - void List(FILE* out = stdout, PRInt32 aIndent = 0) const; - void UnlinkLine(); - PRIntn GetLineNumber() const; - - nsLineData* mNextLine; - nsLineData* mPrevLine; - nsIFrame* mFirstChild; - PRInt32 mChildCount; - PRInt32 mFirstContentOffset; - PRInt32 mLastContentOffset; - nsRect mBounds; - PRPackedBool mLastContentIsComplete; - PRPackedBool mIsBlock; - nsVoidArray* mFloaters; // placeholder frames for below current line floaters -}; - -//---------------------------------------------------------------------- - -/** - * Transient state used during line reflow. - */ - -// State used during line layout that may need to be rewound because -// of an inconvenient word break. -struct nsLineLayoutState { - // The next x coordinate to place the child frame - nscoord mX; - - // This is true if the next frame to reflow should skip over leading - // whitespace. - PRBool mSkipLeadingWhiteSpace; - - // The column number when pre-formatting (for tab spacing) - PRInt32 mColumn; - - // The child frame being considered for reflow - nsIFrame* mKidFrame; - - // The previous child frame just reflowed - nsIFrame* mPrevKidFrame; - - // The child frame's content index-in-parent - PRInt32 mKidIndex; - - // The child frame number within this line - PRInt32 mKidFrameNum; - - // Current line values values - nsSize mMaxElementSize; - nscoord mMaxAscent; - nscoord mMaxDescent; -}; - -struct nsLineLayout { - nsLineLayout(nsBlockReflowState& aState); - ~nsLineLayout(); - - nsresult Initialize(nsBlockReflowState& aState, nsLineData* aLine); - - void SetReflowSpace(nsRect& aAvailableSpaceRect); - - nsresult ReflowLine(); - - nsresult IncrementalReflowFromChild(nsIReflowCommand* aReflowCommand, - nsIFrame* aChildFrame); - - void AtSpace(); - - void AtWordStart(nsIFrame* aFrame, nscoord aX); - - PRBool SkipLeadingWhiteSpace() { - return mState.mSkipLeadingWhiteSpace; - } - - void SetSkipLeadingWhiteSpace(PRBool aSkip) { - mState.mSkipLeadingWhiteSpace = aSkip; - } - - PRIntn GetColumn() { - return mState.mColumn; - } - - void SetColumn(PRIntn aNewColumn) { - mState.mColumn = aNewColumn; - } - - // A value set by line-layout cognizant frames. Frames that are not - // aware of line layout leave the value unchanged and can thus be - // detected by the line-layout algorithm. - PRInt32 mReflowResult; - - // The presentation context - nsIPresContext* mPresContext; - - // The block behind the line - nsBlockFrame* mBlock; - nsBlockReflowState& mBlockReflowState; - nsISpaceManager* mSpaceManager; - nsIContent* mBlockContent; - PRBool mNoWrap; - - // The line we are reflowing - nsLineData* mLine; - nsIFrame* mKidPrevInFlow; - - // Whenever the line layout creates a frame this slot is incremented - PRIntn mNewFrames; - PRIntn mFramesReflowed; - PRIntn mOldChildCount; - - nsLineLayoutState mState; - nsLineLayoutState mSavedState; - - // The current breakable point in the line. If a line-break is - // requested then this is where the line will break at. - nsIFrame* mBreakFrame; - nscoord mBreakX; - PRUint8 mPendingBreak; - - // XXX ick - // This is set by the block code when it updates the available - // reflow area when a floater is placed. - PRBool mReflowDataChanged; - PRPackedBool mMustReflowMappedChildren; - - PRPackedBool mUnconstrainedWidth; - PRPackedBool mUnconstrainedHeight; - PRPackedBool mMarginApplied; - - nscoord mY; - nscoord mLineHeight; - nscoord mMaxWidth; - nscoord mMaxHeight; - nsSize* mMaxElementSizePointer; - nscoord mLeftEdge; - nscoord mRightEdge; - - nscoord* mAscents; - nscoord mAscentBuf[20]; - nscoord mMaxAscents; - -protected: - nsresult SetAscent(nscoord aAscent); - - nsresult ReflowMappedChild(); - - nsresult ReflowChild(nsIReflowCommand* aReflowCommand, PRBool aNewChild); - - nsresult PlaceChild(nsRect& kidRect, - const nsReflowMetrics& kidMetrics, - const nsSize* kidMaxElementSize, - const nsMargin& kidMargin, - nsReflowStatus kidReflowStatus); - - nsresult ReflowMapped(); - - nsresult SplitLine(PRInt32 aChildReflowStatus); - - nsresult PushChildren(); - - nsresult CreateNextInFlow(nsIFrame* aFrame); - - nsresult PullUpChildren(); - - nsresult CreateFrameFor(nsIContent* aKid); - - nsresult ReflowUnmapped(); - - void AlignChildren(); - - PRBool CanBreak(); -}; - -// Value's for nsLineLayout.mReflowResult -#define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0 -#define NS_LINE_LAYOUT_REFLOW_RESULT_AWARE 1 -#define NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER 2 - -// Return value's from nsLineLayout reflow methods -#define NS_LINE_LAYOUT_COMPLETE 0 -#define NS_LINE_LAYOUT_NOT_COMPLETE 1 -#define NS_LINE_LAYOUT_BREAK_BEFORE 2 -#define NS_LINE_LAYOUT_BREAK_AFTER 3 - -#endif /* nsLineLayout_h___ */ diff --git a/mozilla/layout/generic/nsPlaceholderFrame.cpp b/mozilla/layout/generic/nsPlaceholderFrame.cpp index 5ce07ccbb92..d9c74c4c9ea 100644 --- a/mozilla/layout/generic/nsPlaceholderFrame.cpp +++ b/mozilla/layout/generic/nsPlaceholderFrame.cpp @@ -23,8 +23,7 @@ #include "nsIStyleContext.h" #include "nsCSSLayout.h" #include "nsIView.h" - -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +#include "nsHTMLIIDs.h" nsresult nsPlaceholderFrame::NewFrame(nsIFrame** aInstancePtrResult, @@ -112,7 +111,7 @@ nsPlaceholderFrame::Reflow(nsIPresContext* aPresContext, } // Notify our containing block that there's a new floater - container->AddFloater(aPresContext, mAnchoredItem, this); + container->AddFloater(aPresContext, aReflowState, mAnchoredItem, this); } else { // XXX This causes anchored-items sizes to get fixed up; this is @@ -125,7 +124,8 @@ nsPlaceholderFrame::Reflow(nsIPresContext* aPresContext, mAnchoredItem->WillReflow(*aPresContext); mAnchoredItem->Reflow(aPresContext, desiredSize, reflowState, aStatus); mAnchoredItem->SizeTo(desiredSize.width, desiredSize.height); - container->PlaceFloater(aPresContext, mAnchoredItem, this); + +//XXXdeprecated container->PlaceFloater(aPresContext, mAnchoredItem, this); mAnchoredItem->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); } diff --git a/mozilla/layout/html/base/src/Makefile b/mozilla/layout/html/base/src/Makefile index 54c1765b1bd..33deda896ec 100644 --- a/mozilla/layout/html/base/src/Makefile +++ b/mozilla/layout/html/base/src/Makefile @@ -23,7 +23,6 @@ LIBRARY_NAME = raptorhtmlbase_s CPPSRCS = \ nsAbsoluteFrame.cpp \ nsBRPart.cpp \ - nsBlockFrame.cpp \ nsBodyFrame.cpp \ nsBodyPart.cpp \ nsGlobalVariables.cpp \ @@ -41,7 +40,6 @@ CPPSRCS = \ nsHTMLTagContent.cpp \ nsHTMLTags.cpp \ nsImageMap.cpp \ - nsInlineFrame.cpp \ nsLeafFrame.cpp \ nsPageFrame.cpp \ nsPlaceholderFrame.cpp \ diff --git a/mozilla/layout/html/base/src/deadnsInlineFrame.h b/mozilla/layout/html/base/src/deadnsInlineFrame.h deleted file mode 100644 index 8e5eae4f1ea..00000000000 --- a/mozilla/layout/html/base/src/deadnsInlineFrame.h +++ /dev/null @@ -1,102 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#ifndef nsInlineFrame_h___ -#define nsInlineFrame_h___ - -#include "nsHTMLContainerFrame.h" - -class nsInlineState; - -// Inline container class. Does not support being used as a pseudo frame -class nsInlineFrame : public nsHTMLContainerFrame { -public: - static nsresult NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent); - - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); - - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics); - -protected: - nsInlineFrame(nsIContent* aContent, nsIFrame* aParent); - - virtual ~nsInlineFrame(); - - virtual PRIntn GetSkipSides() const; - - void InitializeState(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, - nsInlineState& aState); - - PRBool DidFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - nsReflowMetrics& aChildMetrics); - - PRBool CanFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame); - - void ComputeFinalSize(nsIPresContext* aPresContext, - nsInlineState& aState, - nsReflowMetrics& aSize); - - PRBool ReflowMappedChildrenFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex); - - PRBool PullUpChildren(nsIPresContext* aPresContext, - nsInlineState& aState); - - nsReflowStatus ReflowUnmappedChildren(nsIPresContext* aPresContext, - nsInlineState& aState); - - void PlaceChild(nsIFrame* aChild, - PRInt32 aIndex, // in the child frame list - nsInlineState& aState, - const nsReflowMetrics& aChildSize, - const nsSize* aChildMaxElementSize); - - PRInt32 RecoverState(nsIPresContext* aCX, - nsInlineState& aState, - nsIFrame* aSkipChild); - - nsReflowStatus IncrementalReflowFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex); - - nsReflowStatus IncrementalReflowAfter(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex); - - nsReflowStatus ReflowChild(nsInlineState& aState, - nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState); -}; - -#endif /* nsInlineFrame_h___ */ diff --git a/mozilla/layout/html/base/src/makefile.win b/mozilla/layout/html/base/src/makefile.win index cc6e08f962f..f218fa0f614 100644 --- a/mozilla/layout/html/base/src/makefile.win +++ b/mozilla/layout/html/base/src/makefile.win @@ -23,15 +23,14 @@ REQUIRES=xpcom raptor js DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN CPPSRCS= \ - nsAbsoluteFrame.cpp \ + nsAbsoluteFrame.cpp \ nsBRPart.cpp \ - nsBlockFrame.cpp \ nsBodyFrame.cpp \ nsBodyPart.cpp \ nsGlobalVariables.cpp \ nsHRPart.cpp \ nsHTMLAtoms.cpp \ - nsHTMLBase.cpp \ + nsHTMLBase.cpp \ nsHTMLBullet.cpp \ nsHTMLContainer.cpp \ nsHTMLContainerFrame.cpp \ @@ -39,12 +38,10 @@ CPPSRCS= \ nsHTMLHead.cpp \ nsHTMLIIDs.cpp \ nsHTMLImage.cpp \ - nsHTMLReflowCommand.cpp \ + nsHTMLReflowCommand.cpp \ nsHTMLTagContent.cpp \ nsImageMap.cpp \ - nsInlineFrame.cpp \ nsLeafFrame.cpp \ - nsLineLayout.cpp \ nsPageFrame.cpp \ nsPlaceholderFrame.cpp \ nsRootPart.cpp \ @@ -57,9 +54,8 @@ CPPSRCS= \ $(NULL) CPP_OBJS= \ - .\$(OBJDIR)\nsAbsoluteFrame.obj \ + .\$(OBJDIR)\nsAbsoluteFrame.obj \ .\$(OBJDIR)\nsBRPart.obj \ - .\$(OBJDIR)\nsBlockFrame.obj \ .\$(OBJDIR)\nsBodyFrame.obj \ .\$(OBJDIR)\nsBodyPart.obj \ .\$(OBJDIR)\nsGlobalVariables.obj \ @@ -73,13 +69,11 @@ CPP_OBJS= \ .\$(OBJDIR)\nsHTMLHead.obj \ .\$(OBJDIR)\nsHTMLIIDs.obj \ .\$(OBJDIR)\nsHTMLImage.obj \ - .\$(OBJDIR)\nsHTMLReflowCommand.obj \ + .\$(OBJDIR)\nsHTMLReflowCommand.obj \ .\$(OBJDIR)\nsHTMLTagContent.obj \ .\$(OBJDIR)\nsHTMLTags.obj \ .\$(OBJDIR)\nsImageMap.obj \ - .\$(OBJDIR)\nsInlineFrame.obj \ .\$(OBJDIR)\nsLeafFrame.obj \ - .\$(OBJDIR)\nsLineLayout.obj \ .\$(OBJDIR)\nsPageFrame.obj \ .\$(OBJDIR)\nsPlaceholderFrame.obj \ .\$(OBJDIR)\nsRootPart.obj \ @@ -93,8 +87,9 @@ CPP_OBJS= \ EXPORTS=nsGlobalVariables.h -LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I$(PUBLIC)\js \ - -I..\..\style\src -I$(PUBLIC)\dom -I$(PUBLIC)\netlib \ +LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I$(PUBLIC)\js \ + -I$(PUBLIC)\dom -I$(PUBLIC)\netlib \ + -I..\..\style\src -I..\..\..\css\layout\src \ -I..\..\..\base\src LCFLAGS = \ diff --git a/mozilla/layout/html/base/src/nsBRPart.cpp b/mozilla/layout/html/base/src/nsBRPart.cpp index b24263bebbc..58703a3a109 100644 --- a/mozilla/layout/html/base/src/nsBRPart.cpp +++ b/mozilla/layout/html/base/src/nsBRPart.cpp @@ -20,34 +20,31 @@ #include "nsHTMLTagContent.h" #include "nsHTMLIIDs.h" #include "nsIPresContext.h" -#include "nsBlockFrame.h" +#include "nsIInlineReflow.h" +#include "nsCSSLineLayout.h" #include "nsStyleConsts.h" #include "nsHTMLAtoms.h" #include "nsIStyleContext.h" #include "nsIFontMetrics.h" #include "nsIRenderingContext.h" -class BRFrame : public nsFrame, public nsIInlineFrame { +class BRFrame : public nsFrame, public nsIInlineReflow { public: BRFrame(nsIContent* aContent, nsIFrame* aParentFrame); // nsISupports - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); // nsIFrame NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics); - // nsIInlineFrame - NS_IMETHOD ReflowInline(nsLineLayout& aLineLayout, + // nsIInlineReflow + NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout); + NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout, nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); + const nsReflowState& aReflowState); protected: virtual ~BRFrame(); @@ -63,20 +60,6 @@ BRFrame::~BRFrame() { } -nsrefcnt -BRFrame::AddRef(void) -{ - NS_ERROR("not supported"); - return 0; -} - -nsrefcnt -BRFrame::Release(void) -{ - NS_ERROR("not supported"); - return 0; -} - NS_IMETHODIMP BRFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) { @@ -84,8 +67,8 @@ BRFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } - if (aIID.Equals(kIInlineFrameIID)) { - *aInstancePtrResult = (void*) ((nsIInlineFrame*)this); + if (aIID.Equals(kIInlineReflowIID)) { + *aInstancePtrResult = (void*) ((nsIInlineReflow*)this); return NS_OK; } return nsFrame::QueryInterface(aIID, aInstancePtrResult); @@ -106,9 +89,17 @@ BRFrame::Paint(nsIPresContext& aPresContext, return NS_OK; } -NS_METHOD -BRFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) +NS_IMETHODIMP +BRFrame::FindTextRuns(nsCSSLineLayout& aLineLayout) +{ + aLineLayout.EndTextRun(); + return NS_OK; +} + +NS_IMETHODIMP +BRFrame::InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState) { if (nsnull != aMetrics.maxElementSize) { aMetrics.maxElementSize->width = 0; @@ -116,9 +107,9 @@ BRFrame::GetReflowMetrics(nsIPresContext* aPresContext, } // We have no width, but we're the height of the default font - const nsStyleFont* font = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - nsIFontMetrics* fm = aPresContext->GetMetricsFor(font->mFont); + const nsStyleFont* font = (const nsStyleFont*) + mStyleContext->GetStyleData(eStyleStruct_Font); + nsIFontMetrics* fm = aLineLayout.mPresContext->GetMetricsFor(font->mFont); aMetrics.width = 0; if (nsIFrame::GetShowFrameBorders()) { @@ -132,45 +123,16 @@ BRFrame::GetReflowMetrics(nsIPresContext* aPresContext, aMetrics.descent = fm->GetMaxDescent(); NS_RELEASE(fm); - // Get cached state for containing block frame - nsBlockReflowState* state = - nsBlockFrame::FindBlockReflowState(aPresContext, this); - if (nsnull != state) { - nsLineLayout* lineLayoutState = state->mCurrentLine; - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = - NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER; - const nsStyleDisplay* display = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - lineLayoutState->mPendingBreak = display->mBreakType; - if (NS_STYLE_CLEAR_NONE == lineLayoutState->mPendingBreak) { - lineLayoutState->mPendingBreak = NS_STYLE_CLEAR_LINE; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -BRFrame::ReflowInline(nsLineLayout& aLineLayout, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - GetReflowMetrics(aLineLayout.mPresContext, aDesiredSize); - aStatus = NS_FRAME_COMPLETE; - - aLineLayout.mReflowResult = - NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER; + // Return our inline reflow status const nsStyleDisplay* display = (const nsStyleDisplay*) mStyleContext->GetStyleData(eStyleStruct_Display); - aLineLayout.mPendingBreak = display->mBreakType; - if (NS_STYLE_CLEAR_NONE == aLineLayout.mPendingBreak) { - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_LINE; + PRUint32 breakType = display->mBreakType; + if (NS_STYLE_CLEAR_NONE == breakType) { + breakType = NS_STYLE_CLEAR_LINE; } - return NS_OK; + return NS_INLINE_REFLOW_BREAK_AFTER | + NS_INLINE_REFLOW_MAKE_BREAK_TYPE(breakType); } //---------------------------------------------------------------------- diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h deleted file mode 100644 index 77b3e0ee8ff..00000000000 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ /dev/null @@ -1,313 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#ifndef nsBlockFrame_h___ -#define nsBlockFrame_h___ - -#include "nsHTMLContainerFrame.h" -#include "nsIFloaterContainer.h" -#include "nsIRunaround.h" -#include "nsISpaceManager.h" -#include "nsLineLayout.h" -#include "nsVoidArray.h" - -struct nsMargin; -struct nsStyleDisplay; -struct nsStyleFont; -struct nsStyleText; -class nsBlockFrame; -struct nsBandData; - -struct nsBlockBandData : public nsBandData { - // Trapezoids used during band processing - nsBandTrapezoid data[12]; - - // Bounding rect of available space between any left and right floaters - nsRect availSpace; - - nsBlockBandData() { - size = 12; - trapezoids = data; - } - - /** - * Computes the bounding rect of the available space, i.e. space - * between any left and right floaters Uses the current trapezoid - * data, see nsISpaceManager::GetBandData(). Also updates member - * data "availSpace". - */ - void ComputeAvailSpaceRect(); -}; - -struct nsBlockReflowState { - nsBlockReflowState(); - ~nsBlockReflowState(); - - nsresult Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock); - - nsresult RecoverState(nsLineData* aLine); - - nsIPresContext* mPresContext; - - nsBlockFrame* mBlock; - PRBool mBlockIsPseudo; - - // Current line being reflowed - nsLineLayout* mCurrentLine; - - // Previous line's last child frame - nsIFrame* mPrevKidFrame; - - // Layout position information - nscoord mX; - nscoord mY; - nsSize mAvailSize; - nsSize mStyleSize; - PRIntn mStyleSizeFlags; - PRPackedBool mUnconstrainedWidth; - PRPackedBool mUnconstrainedHeight; - nsSize* mMaxElementSizePointer; - nscoord mKidXMost; - const nsReflowState* reflowState; - - // Change in width since last reflow - nscoord mDeltaWidth; - - // Bottom margin information from the previous line (only when - // the previous line contains a block element) - nscoord mPrevNegBottomMargin; - nscoord mPrevPosBottomMargin; - PRBool mPrevMarginSynthetic; - - // Block frame border+padding information - nsMargin mBorderPadding; - - // Space manager and current band information - nsISpaceManager* mSpaceManager; - nsBlockBandData mCurrentBand; - - // Array of floaters to place below current line - nsVoidArray mPendingFloaters; - - // The next list ordinal for counting list bullets - PRInt32 mNextListOrdinal; - PRBool mListPositionOutside; -}; - -//---------------------------------------------------------------------- - -/* 94e8e410-de21-11d1-89bf-006008911b81 */ -#define NS_BLOCKFRAME_CID \ - {0x94e8e410, 0xde21, 0x11d1, {0x89, 0xbf, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} - -/** - *

Block Reflow

- * - * The block frame reflow machinery performs "2D" layout. Inline - * elements are flowed into logical lines (left to right or right to - * left) and the lines are stacked vertically. nsLineLayout is used - * for this part of the process. Block elements are flowed directly by - * the block reflow logic after flushing out any preceeding line.

- * - * During reflow, the block frame will make available to child frames - * it's reflow state using the presentation shell's cached data - * mechanism.

- * - *

Reflowing Mapped Content

- *

Pullup

- *

Reflowing Unmapped Content

- *

Content Insertion Handling

- *

Content Deletion Handling

- *

Style Change Handling

- * - *

Assertions

- * mLastContentIsComplete always reflects the state of the last - * child frame on our chlid list. - */ - -// XXX we don't use nsContainerFrame mOverFlowList!!! wasted memory - -class nsBlockFrame : public nsHTMLContainerFrame, - public nsIRunaround, - public nsIFloaterContainer -{ -public: - /** - * Create a new block frame that maps the given piece of content. - */ - static nsresult NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent); - - // nsISupports - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - - // nsIFrame - NS_IMETHOD ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer); - NS_IMETHOD ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent); - NS_IMETHOD ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent); - NS_IMETHOD ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent); - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics); - NS_IMETHOD IsSplittable(nsSplittableType& aIsSplittable) const; - NS_IMETHOD CreateContinuingFrame(nsIPresContext* aPresContext, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame); - NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const; - NS_IMETHOD ListTag(FILE* out) const; - NS_IMETHOD VerifyTree() const; - - // nsIRunaround - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus); - - // nsIFloaterContainer - virtual PRBool AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder); - virtual void PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder); - - // nsBlockFrame - nsresult ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); - - nsresult ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus); - - static nsBlockReflowState* FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame); - -protected: - nsBlockFrame(nsIContent* aContent, nsIFrame* aParent); - - virtual ~nsBlockFrame(); - - virtual PRIntn GetSkipSides() const; - - virtual void WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow); - - nsresult InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState); - - void ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect); - - nsLineData* LastLine(); - nsLineData* FindLine(nsIFrame* aFrame); - - nsresult IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds); - - void DestroyLines(); - - void DrainOverflowList(); - - nsLineData* CreateLineForOverflowList(nsIFrame* aOverflowList); - -#ifdef NS_DEBUG - nsresult VerifyLines(PRBool aFinalCheck) const; -#endif - - void ClearFloaters(nsBlockReflowState& aState, - PRUint8 aBreakType); - - nsresult PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine); - - PRBool IsLeftMostChild(nsIFrame* aFrame); - - void PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState); - void PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY); - - nsresult GetAvailableSpace(nsBlockReflowState& aState, nscoord aY); - - PRBool MoreToReflow(nsBlockReflowState& aState); - - nsresult PushLines(nsBlockReflowState& aState, - nsLineData* aLine); - - nsresult ReflowMapped(nsBlockReflowState& aState); - nsresult ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine); - - nsresult ReflowUnmapped(nsBlockReflowState& aState); - - nsLineData* GetFirstLine(); - - void ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame); - - void SetFirstChild(nsIFrame* aFirstChild) { - if (nsnull == mFirstChild) { - mFirstChild = aFirstChild; - } - } - - nsLineData* mLines; - nsVoidArray* mRunInFloaters; // placeholder frames for floaters to display - // at the top line - - friend struct nsLineLayout; -}; - -#endif /* nsBlockFrame_h___ */ diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h deleted file mode 100644 index bf4fc11255c..00000000000 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ /dev/null @@ -1,1961 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsBlockFrame.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIHTMLContent.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsIAnchoredItems.h" -#include "nsIReflowCommand.h" -#include "nsPlaceholderFrame.h" -#include "nsIPtr.h" -#include "nsHTMLAtoms.h" -#include "nsHTMLIIDs.h" -#include "nsHTMLValue.h" -#include "nsCSSLayout.h" -#include "nsIView.h" - -// XXX what do we do with catastrophic errors (rv < 0)? What is the -// state of the reflow world after such an error? - -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -//---------------------------------------------------------------------- - -void nsBlockBandData::ComputeAvailSpaceRect() -{ - nsBandTrapezoid* trapezoid = data; - - if (count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < count; i++) { - nsBandTrapezoid* trapezoid = &data[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &data[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availSpace); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availSpace); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availSpace.x = availSpace.XMost(); - } - availSpace.width = 0; - } -} - -//---------------------------------------------------------------------- - -nsBlockReflowState::nsBlockReflowState() -{ -} - -nsBlockReflowState::~nsBlockReflowState() -{ -} - -nsresult -nsBlockReflowState::Initialize(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockFrame* aBlock) -{ - nsresult rv = NS_OK; - - mPresContext = aPresContext; - mBlock = aBlock; - mSpaceManager = aSpaceManager; - mBlockIsPseudo = aBlock->IsPseudoFrame(); - mListPositionOutside = PR_FALSE; - mCurrentLine = nsnull; - mPrevKidFrame = nsnull; - reflowState = &aReflowState; - - mX = 0; - mY = 0; - mStyleSizeFlags = 0; - mAvailSize = reflowState->maxSize; - mUnconstrainedWidth = PRBool(mAvailSize.width == NS_UNCONSTRAINEDSIZE); - mUnconstrainedHeight = PRBool(mAvailSize.height == NS_UNCONSTRAINEDSIZE); - mMaxElementSizePointer = aMaxElementSize; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; - } - mKidXMost = 0; - - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = 0; - mPrevMarginSynthetic = PR_FALSE; - - mNextListOrdinal = -1; - - return rv; -} - -// Recover the block reflow state to what it should be if aLine is about -// to be reflowed. aLine should not be nsnull -nsresult nsBlockReflowState::RecoverState(nsLineData* aLine) -{ - NS_PRECONDITION(nsnull != aLine, "null parameter"); - nsLineData* prevLine = aLine->mPrevLine; - - if (nsnull != prevLine) { - // Compute the running y-offset, and the available height - mY = prevLine->mBounds.YMost(); - if (!mUnconstrainedHeight) { - mAvailSize.height -= mY; - } - - // Compute the kid x-most - for (nsLineData* l = prevLine; nsnull != l; l = l->mPrevLine) { - nscoord xmost = l->mBounds.XMost(); - if (xmost > mKidXMost) { - mKidXMost = xmost; - } - } - - // If the previous line is a block, then factor in its bottom margin - if (prevLine->mIsBlock) { - const nsStyleSpacing* kidSpacing; - nsIFrame* kid = prevLine->mFirstChild; - - kid->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)kidSpacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kid, kidMargin); - if (kidMargin.bottom < 0) { - mPrevPosBottomMargin = 0; - mPrevNegBottomMargin = -kidMargin.bottom; - } else { - mPrevPosBottomMargin = kidMargin.bottom; - mPrevNegBottomMargin = 0; - } - } - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult -nsBlockFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsBlockFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsBlockFrame::nsBlockFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ -} - -nsBlockFrame::~nsBlockFrame() -{ - DestroyLines(); - delete mRunInFloaters; -} - -void nsBlockFrame::DestroyLines() -{ - nsLineData* line = mLines; - while (nsnull != line) { - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - mLines = nsnull; -} - -NS_METHOD -nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - NS_PRECONDITION(0 != aInstancePtr, "null ptr"); - if (NULL == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kBlockFrameCID)) { - *aInstancePtr = (void*) (this); - return NS_OK; - } - else if (aIID.Equals(kIRunaroundIID)) { - *aInstancePtr = (void*) ((nsIRunaround*) this); - return NS_OK; - } - else if (aIID.Equals(kIFloaterContainerIID)) { - *aInstancePtr = (void*) ((nsIFloaterContainer*) this); - return NS_OK; - } - return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr); -} - -NS_METHOD -nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const -{ - aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::CreateContinuingFrame(nsIPresContext* aCX, - nsIFrame* aParent, - nsIStyleContext* aStyleContext, - nsIFrame*& aContinuingFrame) -{ - nsBlockFrame* cf = new nsBlockFrame(mContent, aParent); - if (nsnull == cf) { - return NS_ERROR_OUT_OF_MEMORY; - } - PrepareContinuingFrame(aCX, aParent, aStyleContext, cf); - aContinuingFrame = cf; - return NS_OK; -} - -NS_METHOD -nsBlockFrame::ListTag(FILE* out) const -{ - if ((nsnull != mGeometricParent) && IsPseudoFrame()) { - fprintf(out, "*block<"); - nsIAtom* atom = mContent->GetTag(); - if (nsnull != atom) { - nsAutoString tmp; - atom->ToString(tmp); - fputs(tmp, out); - } - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, ">(%d)@%p", contentIndex, this); - } else { - nsHTMLContainerFrame::ListTag(out); - } - return NS_OK; -} - -NS_METHOD -nsBlockFrame::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the tag - ListTag(out); - nsIView* view; - GetView(view); - if (nsnull != view) { - fprintf(out, " [view=%p]", view); - NS_RELEASE(view); - } - - // Output the first/last content offset - fprintf(out, "[%d,%d,%c] ", mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - if (nsnull != mPrevInFlow) { - fprintf(out, "prev-in-flow=%p ", mPrevInFlow); - } - if (nsnull != mNextInFlow) { - fprintf(out, "next-in-flow=%p ", mNextInFlow); - } - - // Output the rect - out << mRect; - - // Output the children, one line at a time - if (nsnull != mLines) { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<\n", out); - aIndent++; - - nsLineData* line = mLines; - while (nsnull != line) { - line->List(out, aIndent); - line = line->mNextLine; - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - if (0 != mState) { - fprintf(out, " [state=%08x]", mState); - } - fputs("<>\n", out); - } - - return NS_OK; -} - -NS_METHOD -nsBlockFrame::VerifyTree() const -{ -#ifdef NS_DEBUG - NS_ASSERTION(0 == (mState & NS_FRAME_IN_REFLOW), "frame is in reflow"); - nsresult rv = nsHTMLContainerFrame::VerifyTree(); - if (NS_OK != rv) { - return rv; - } - rv = VerifyLines(PR_TRUE); - return rv; -#else - return NS_OK; -#endif -} - -#ifdef NS_DEBUG -nsresult -nsBlockFrame::VerifyLines(PRBool aFinalCheck) const -{ - nsresult rv = NS_OK; - - // Make sure that the list of children agrees with our child count. - // If this is not the case then the child list and the line list are - // not properly arranged. - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(mChildCount == len, "bad child list"); - - // Verify that our lines are correctly setup - PRInt32 offset = mFirstContentOffset; - PRInt32 lineChildCount = 0; - nsLineData* line = mLines; - nsLineData* prevLine = nsnull; - while (nsnull != line) { - if (aFinalCheck) { - NS_ASSERTION(((offset == line->mFirstContentOffset) && - (line->mFirstContentOffset <= line->mLastContentOffset)), - "bad line mFirstContentOffset"); - NS_ASSERTION(line->mLastContentOffset <= mLastContentOffset, - "bad line mLastContentOffset"); - offset = line->mLastContentOffset; - if (line->mLastContentIsComplete) { - offset++; - } - } - lineChildCount += line->mChildCount; - rv = line->Verify(aFinalCheck); - if (NS_OK != rv) { - return rv; - } - prevLine = line; - line = line->mNextLine; - } - if (aFinalCheck && (nsnull != prevLine)) { - NS_ASSERTION(prevLine->mLastContentOffset == mLastContentOffset, - "bad mLastContentOffset"); - NS_ASSERTION(prevLine->mLastContentIsComplete == mLastContentIsComplete, - "bad mLastContentIsComplete"); - } - NS_ASSERTION(lineChildCount == mChildCount, "bad line counts"); - - return rv; -} -#endif - -//---------------------------------------------------------------------- - -// Remove a next-in-flow from from this block's list of lines - -// XXX problems here: -// 1. we always have to start from the first line: slow! -// 2. we can avoid this when the child is not the last child in a line - -void -nsBlockFrame::WillDeleteNextInFlowFrame(nsIFrame* aNextInFlow) -{ - // When a reflow indicates completion it's possible that - // next-in-flows were just removed. We have to remove them from any - // nsLineData's that follow the current line. - nsLineData* line = mLines; - while (nsnull != line) { - if (line->mFirstChild == aNextInFlow) { - // Remove child from line. - if (0 == --line->mChildCount) { - line->mFirstChild = nsnull; - } - else { - // Fixup the line - nsIFrame* nextKid; - aNextInFlow->GetNextSibling(nextKid); - line->mFirstChild = nextKid; - nextKid->GetContentIndex(line->mFirstContentOffset); - } - break; - } - line = line->mNextLine; - } -} - -nsresult -nsBlockFrame::ReflowInlineChild(nsLineLayout& aLineLayout, - nsIFrame* aKidFrame, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(aLineLayout, aDesiredSize, aReflowState, aStatus); - } - else { - aKidFrame->Reflow(aLineLayout.mPresContext, aDesiredSize, aReflowState, - aStatus); - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return NS_OK; -} - -nsresult -nsBlockFrame::ReflowBlockChild(nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ - nsIRunaround* reflowRunaround; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - - // Get the band for this y-offset and see whether there are any floaters - // that have changed the left/right edges. - // - // XXX In order to do this efficiently we should move all this code to - // nsBlockFrame since it already has band data, and it's probably the only - // one who calls this routine anyway - nsBandData bandData; - nsBandTrapezoid trapezoids[12]; - nsBandTrapezoid* trapezoid = trapezoids; - nsRect availBand; - - bandData.trapezoids = trapezoids; - bandData.size = 12; - aSpaceManager->GetBandData(0, aReflowState.maxSize, bandData); - - if (bandData.count > 1) { - // If there's more than one trapezoid that means there are floaters - PRInt32 i; - - // Stop when we get to space occupied by a right floater, or when we've - // looked at every trapezoid and none are right floaters - for (i = 0; i < bandData.count; i++) { - nsBandTrapezoid* trapezoid = &trapezoids[i]; - - if (trapezoid->state != nsBandTrapezoid::Available) { - const nsStyleDisplay* display; - - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 numFrames = trapezoid->frames->Count(); - - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (PRInt32 i = 0; i < numFrames; i++) { - nsIFrame* f = (nsIFrame*)trapezoid->frames->ElementAt(i); - - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - goto foundRightFloater; - } - } - - } else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_RIGHT == display->mFloats) { - break; - } - } - } - } - foundRightFloater: - - if (i > 0) { - trapezoid = &trapezoids[i - 1]; - } - } - - if (nsBandTrapezoid::Available == trapezoid->state) { - // The trapezoid is available - trapezoid->GetRect(availBand); - } else { - const nsStyleDisplay* display; - - // The trapezoid is occupied. That means there's no available space - trapezoid->GetRect(availBand); - - // XXX Handle the case of multiple frames - trapezoid->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - if (NS_STYLE_FLOAT_LEFT == display->mFloats) { - availBand.x = availBand.XMost(); - } - availBand.width = 0; - } - - // Does the child frame support interface nsIRunaround? - if (NS_OK == aKidFrame->QueryInterface(kIRunaroundIID, - (void**)&reflowRunaround)) { - // Yes, the child frame wants to interact directly with the space - // manager. - reflowRunaround->Reflow(aPresContext, aSpaceManager, aDesiredSize, aReflowState, - aDesiredRect, aStatus); - } else { - // No, use interface nsIFrame instead. - if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) { - if ((availBand.x > 0) || (availBand.XMost() < aReflowState.maxSize.width)) { - // There are left/right floaters. - aReflowState.maxSize.width = availBand.width; - } - } - - // XXX FIX ME - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Return the desired rect - aDesiredRect.x = availBand.x; - aDesiredRect.y = 0; - aDesiredRect.width = aDesiredSize.width; - aDesiredRect.height = aDesiredSize.height; - } - - if (NS_FRAME_IS_COMPLETE(aStatus)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - - return NS_OK; -} - -nsLineData* -nsBlockFrame::CreateLineForOverflowList(nsIFrame* aOverflowList) -{ - nsLineData* newLine = new nsLineData(); - if (nsnull != newLine) { - nsIFrame* kid = aOverflowList; - newLine->mFirstChild = kid; - kid->GetContentIndex(newLine->mFirstContentOffset); - newLine->mLastContentOffset = -1; - newLine->mLastContentIsComplete = PRPackedBool(0x255); - PRInt32 kids = 0; - while (nsnull != kid) { - kids++; - kid->GetNextSibling(kid); - } - newLine->mChildCount = kids; - } - return newLine; -} - -void -nsBlockFrame::DrainOverflowList() -{ - nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow; - if (nsnull != prevBlock) { - nsIFrame* overflowList = prevBlock->mOverflowList; - if (nsnull != overflowList) { - NS_ASSERTION(nsnull == mFirstChild, "bad overflow list"); - NS_ASSERTION(nsnull == mLines, "bad overflow list"); - - // Create a line to hold the entire overflow list - nsLineData* newLine = CreateLineForOverflowList(overflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(overflowList); - prevBlock->mOverflowList = nsnull; - - // The new line is the first line - mLines = newLine; - } - } - - if (nsnull != mOverflowList) { - NS_ASSERTION(nsnull != mFirstChild, - "overflow list but no mapped children"); - - // Create a line to hold the overflow list - nsLineData* newLine = CreateLineForOverflowList(mOverflowList); - - // Place the children on our child list; this also reassigns - // their geometric parent and updates our mChildCount. - AppendChildren(mOverflowList, PR_FALSE); - mOverflowList = nsnull; - - // The new line is appended after our other lines - nsLineData* prevLine = nsnull; - nsLineData* line = mLines; - while (nsnull != line) { - prevLine = line; - line = line->mNextLine; - } - if (nsnull == prevLine) { - mLines = newLine; - } - else { - prevLine->mNextLine = newLine; - newLine->mPrevLine = prevLine; - } - } -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_FALSE); - } -#endif -} - -void -nsBlockFrame::ClearFloaters(nsBlockReflowState& aState, PRUint8 aBreakType) -{ - for (;;) { - if (aState.mCurrentBand.count <= 1) { - // No floaters in this band therefore nothing to clear - break; - } - - // Find the Y coordinate to clear to - nscoord clearYMost = aState.mY; - nsRect tmp; - PRInt32 i; - for (i = 0; i < aState.mCurrentBand.count; i++) { - const nsStyleDisplay* display; - nsBandTrapezoid* trapezoid = &aState.mCurrentBand.data[i]; - if (trapezoid->state != nsBandTrapezoid::Available) { - if (nsBandTrapezoid::OccupiedMultiple == trapezoid->state) { - PRInt32 fn, numFrames = trapezoid->frames->Count(); - NS_ASSERTION(numFrames > 0, "bad trapezoid frame list"); - for (fn = 0; fn < numFrames; fn++) { - nsIFrame* f = (nsIFrame*) trapezoid->frames->ElementAt(fn); - f->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - else { - trapezoid->frame->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&)display); - switch (display->mFloats) { - case NS_STYLE_FLOAT_LEFT: - if ((NS_STYLE_CLEAR_LEFT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - case NS_STYLE_FLOAT_RIGHT: - if ((NS_STYLE_CLEAR_RIGHT == aBreakType) || - (NS_STYLE_CLEAR_LEFT_AND_RIGHT == aBreakType)) { - trapezoid->GetRect(tmp); - nscoord ym = tmp.YMost(); - if (ym > clearYMost) { - clearYMost = ym; - } - } - break; - } - } - } - } - - if (clearYMost == aState.mY) { - // Nothing to clear - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsBlockFrame::ClearFloaters: mY=%d clearYMost=%d\n", - aState.mY, clearYMost)); - - aState.mY = clearYMost + 1; - - // Get a new band - GetAvailableSpace(aState, aState.mY); - } -} - -nsresult -nsBlockFrame::PlaceLine(nsBlockReflowState& aState, - nsLineLayout& aLineLayout, - nsLineData* aLine) -{ - // Before we place the line, make sure that it will fit in it's new - // location. It always fits if the height isn't constrained or it's - // the first line. - if (!aState.mUnconstrainedHeight && (aLine != mLines)) { - if (aState.mY + aLine->mBounds.height > aState.mAvailSize.height) { - // The line will not fit - return PushLines(aState, aLine); - } - } - - // When the line is finally placed then we know that the child - // frames have a stable location. This means that we can DidReflow - // them marking them done. Note that when we are paginated this - // optimization cannot be done because this may be a nested block - // that will be pushed to a new page by the containing block and the - // nested block can't know that during its reflow. - // XXX and actually, this only always works for the block which is a - // child of the body. - if (!aState.mPresContext->IsPaginated()) { - nsIAtom* tag = mContent->GetTag(); - if (nsHTMLAtoms::body == tag) { - nsIFrame* child = aLine->mFirstChild; - for (PRInt32 i = aLine->mChildCount; --i >= 0; ) { - nsFrameState state; - child->GetFrameState(state); - if (NS_FRAME_IN_REFLOW & state) { - child->DidReflow(*aState.mPresContext, NS_FRAME_REFLOW_FINISHED); - } - child->GetNextSibling(child); - } - - // Paint this portion of ourselves - if (!aLine->mBounds.IsEmpty()) { - Invalidate(aLine->mBounds); - } - } - NS_IF_RELEASE(tag); - } - - // Consume space and advance running values - aState.mY += aLine->mBounds.height; - if (nsnull != aState.mMaxElementSizePointer) { - nsSize* maxSize = aState.mMaxElementSizePointer; - if (aLineLayout.mState.mMaxElementSize.width > maxSize->width) { - maxSize->width = aLineLayout.mState.mMaxElementSize.width; - } - if (aLineLayout.mState.mMaxElementSize.height > maxSize->height) { - maxSize->height = aLineLayout.mState.mMaxElementSize.height; - } - } - nscoord xmost = aLine->mBounds.XMost(); - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; - } - - // Process any pending break operations - switch (aLineLayout.mPendingBreak) { - default: - break; - case NS_STYLE_CLEAR_LEFT: - case NS_STYLE_CLEAR_RIGHT: - case NS_STYLE_CLEAR_LEFT_AND_RIGHT: - ClearFloaters(aState, aLineLayout.mPendingBreak); - break; - } - // XXX for now clear the pending break; this is where support for - // page breaks or column breaks could be partially handled. - aLineLayout.mPendingBreak = NS_STYLE_CLEAR_NONE; - - // Any below current line floaters to place? - // XXX We really want to know whether this is the initial reflow (reflow - // unmapped) or a subsequent reflow in which case we only need to offset - // the existing floaters... - if (aState.mPendingFloaters.Count() > 0) { - if (nsnull == aLine->mFloaters) { - aLine->mFloaters = new nsVoidArray; - } - aLine->mFloaters->operator=(aState.mPendingFloaters); - aState.mPendingFloaters.Clear(); - } - - if (nsnull != aLine->mFloaters) { - PlaceBelowCurrentLineFloaters(aState, aLine->mFloaters, aState.mY); - // XXX Factor in the height of the floaters as well when considering - // whether the line fits. - // The default policy is that if there isn't room for the floaters then - // both the line and the floaters are pushed to the next-in-flow... - } - - if (aState.mY >= aState.mCurrentBand.availSpace.YMost()) { - // The current y coordinate is now past our available space - // rectangle. Get a new band of space. - GetAvailableSpace(aState, aState.mY); - } - - return NS_LINE_LAYOUT_COMPLETE; -} - -// aY has borderpadding.top already factored in -nsresult -nsBlockFrame::GetAvailableSpace(nsBlockReflowState& aState, nscoord aY) -{ - nsresult rv = NS_OK; - - nsISpaceManager* sm = aState.mSpaceManager; - - // Fill in band data for the specific Y coordinate - sm->Translate(aState.mBorderPadding.left, 0); - sm->GetBandData(aY, aState.mAvailSize, aState.mCurrentBand); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Compute the bounding rect of the available space, i.e. space - // between any left and right floaters - aState.mCurrentBand.ComputeAvailSpaceRect(); - - aState.mCurrentBand.availSpace.MoveBy(aState.mBorderPadding.left, - aState.mY); - - return rv; -} - -// Give aLine and any successive lines to the block's next-in-flow; if -// we don't have a next-in-flow then push all the children onto our -// overflow list. -nsresult -nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineData* aLine) -{ - PRInt32 i; - - // Split our child-list in two; revert our last content offset and - // completion status to the previous line. - nsLineData* prevLine = aLine->mPrevLine; - NS_PRECONDITION(nsnull != prevLine, "pushing first line"); - nsIFrame* prevKidFrame = prevLine->mFirstChild; - for (i = prevLine->mChildCount - 1; --i >= 0; ) { - prevKidFrame->GetNextSibling(prevKidFrame); - } -#ifdef NS_DEBUG - nsIFrame* nextFrame; - prevKidFrame->GetNextSibling(nextFrame); - NS_ASSERTION(nextFrame == aLine->mFirstChild, "bad line list"); -#endif - prevKidFrame->SetNextSibling(nsnull); - prevLine->mNextLine = nsnull; - mLastContentOffset = prevLine->mLastContentOffset; - mLastContentIsComplete = prevLine->mLastContentIsComplete; - - // Push children to our next-in-flow if we have, or to our overflow list - nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow; - PRInt32 pushCount = 0; - if (nsnull == nextInFlow) { - // Place children on the overflow list - mOverflowList = aLine->mFirstChild; - - // Destroy the lines - nsLineData* line = aLine; - while (nsnull != line) { - pushCount += line->mChildCount; - nsLineData* next = line->mNextLine; - delete line; - line = next; - } - } - else { - aLine->mPrevLine = nsnull; - - // Pass on the children to our next-in-flow - nsLineData* line = aLine; - prevLine = line; - nsIFrame* lastKid = aLine->mFirstChild; - nsIFrame* kid = lastKid; - while (nsnull != line) { - i = line->mChildCount; - pushCount += i; - NS_ASSERTION(kid == line->mFirstChild, "bad line list"); - while (--i >= 0) { - kid->SetGeometricParent(nextInFlow); - nsIFrame* contentParent; - kid->GetContentParent(contentParent); - if (this == contentParent) { - kid->SetContentParent(nextInFlow); - } - lastKid = kid; - kid->GetNextSibling(kid); - } - prevLine = line; - line = line->mNextLine; - } - - // Join the two line lists - nsLineData* nextInFlowLine = nextInFlow->mLines; - if (nsnull != nextInFlowLine) { - lastKid->SetNextSibling(nextInFlowLine->mFirstChild); - nextInFlowLine->mPrevLine = prevLine; - } - nsIFrame* firstKid = aLine->mFirstChild; - prevLine->mNextLine = nextInFlowLine; - nextInFlow->mLines = aLine; - nextInFlow->mFirstChild = firstKid; - nextInFlow->mChildCount += pushCount; - firstKid->GetContentIndex(nextInFlow->mFirstContentOffset); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - nextInFlow->VerifyLines(PR_FALSE); - } -#endif - } - mChildCount -= pushCount; - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return NS_LINE_LAYOUT_NOT_COMPLETE; -} - -nsresult -nsBlockFrame::ReflowMapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // See if we have any run-in floaters to place - if (nsnull != mRunInFloaters) { - PlaceBelowCurrentLineFloaters(aState, mRunInFloaters, aState.mY); - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - nsLineData* line = mLines; - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != line) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line);/* XXX move out of loop */ - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -// XXX This is a short-term hack. It assumes that the caller has already recovered -// the state, and that some space has been retrieved from the space manager... -nsresult -nsBlockFrame::ReflowMappedFrom(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - while (nsnull != aLine) { - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, aLine); - if (NS_OK != rv) { - goto done; - } - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, aLine); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - - mLastContentOffset = aLine->mLastContentOffset; - mLastContentIsComplete = PRBool(aLine->mLastContentIsComplete); - aLine = aLine->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::ReflowUnmapped(nsBlockReflowState& aState) -{ - nsresult rv = NS_OK; - - // If we have no children and we have a prev-in-flow then we need to - // pick up where it left off. If we have children, e.g. we're being - // resized, then our content offset will have already been set - // correctly. - nsIFrame* kidPrevInFlow = nsnull; - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsBlockFrame* prev = (nsBlockFrame*) mPrevInFlow; - mFirstContentOffset = prev->NextChildOffset();// XXX Is this necessary? - if (PR_FALSE == prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - - // Get to the last line where the new content may be added - nsLineData* line = nsnull; - nsLineData* prevLine = nsnull; - if (nsnull != mLines) { - line = mLines; - while (nsnull != line->mNextLine) { - line = line->mNextLine; - } - prevLine = line->mPrevLine; - - // If the last line is not complete then kidPrevInFlow should be - // set to the last-line's last child. - if (!line->mLastContentIsComplete) { - kidPrevInFlow = line->GetLastChild(); - } - } - - // Get some space to start reflowing with - GetAvailableSpace(aState, aState.mY); - - // Now reflow the new content until we are out of new content or out - // of vertical space. - PRInt32 kidIndex = NextChildOffset(); - nsLineLayout lineLayout(aState); - aState.mCurrentLine = &lineLayout; - lineLayout.mKidPrevInFlow = kidPrevInFlow; - PRInt32 contentChildCount = mContent->ChildCount(); - while (kidIndex < contentChildCount) { - if (nsnull == line) { - if (!MoreToReflow(aState)) { - break; - } - line = new nsLineData(); - if (nsnull == line) { - rv = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - line->mFirstContentOffset = kidIndex; - } - - // Initialize the line layout for this line - rv = lineLayout.Initialize(aState, line); - if (NS_OK != rv) { - goto done; - } - lineLayout.mKidPrevInFlow = kidPrevInFlow; - lineLayout.mState.mPrevKidFrame = aState.mPrevKidFrame; - - // Reflow the line - nsresult lineReflowStatus = lineLayout.ReflowLine(); - if (PRInt32(lineReflowStatus) < 0) { - // Some kind of hard error - rv = lineReflowStatus; - goto done; - } - mChildCount += lineLayout.mNewFrames; - - // Add line to the block; do this before placing the line in case - // PushLines is needed. - if (nsnull == prevLine) { - // For the first line, initialize mFirstContentOffset - mFirstContentOffset = line->mFirstContentOffset; - mFirstChild = line->mFirstChild; - mLines = line; - } - else { - prevLine->mNextLine = line; - line->mPrevLine = prevLine; - } - - // Now place it. It's possible it won't fit. - rv = PlaceLine(aState, lineLayout, line); - if (NS_LINE_LAYOUT_COMPLETE != rv) { - goto done; - } - kidIndex = lineLayout.mState.mKidIndex; - kidPrevInFlow = lineLayout.mKidPrevInFlow; - - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - prevLine = line; - line = line->mNextLine; - aState.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - } - -done: - aState.mCurrentLine = nsnull; - if (aState.mBlockIsPseudo) { - PropagateContentOffsets(); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - } -#endif - return rv; -} - -nsresult -nsBlockFrame::InitializeState(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize, - nsBlockReflowState& aState) -{ - nsresult rv; - rv = aState.Initialize(aPresContext, aSpaceManager, - aReflowState, aMaxElementSize, this); - - // Apply border and padding adjustments for regular frames only - if (!aState.mBlockIsPseudo) { - const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStylePosition* myPosition = (const nsStylePosition*) - mStyleContext->GetStyleData(eStyleStruct_Position); - - mySpacing->CalcBorderPaddingFor(this, aState.mBorderPadding); - aState.mY = aState.mBorderPadding.top; - aState.mX = aState.mBorderPadding.left; - - if (aState.mUnconstrainedWidth) { - // If our width is unconstrained don't bother futzing with the - // available width/height because they don't matter - we are - // going to get reflowed again. - aState.mDeltaWidth = NS_UNCONSTRAINEDSIZE; - } - else { - // When we are constrained we need to apply the width/height - // style properties. When we have a width/height it applies to - // the content width/height of our box. The content width/height - // doesn't include the border+padding so we have to add that in - // instead of subtracting it out of our maxsize. - nscoord lr = - aState.mBorderPadding.left + aState.mBorderPadding.right; - - // Get and apply the stylistic size. Note: do not limit the - // height until we are done reflowing. - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, - aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aState.mAvailSize.width = aState.mStyleSize.width + lr; - } - else { - aState.mAvailSize.width -= lr; - } - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - } - else { - aState.mBorderPadding.SizeTo(0, 0, 0, 0); - aState.mDeltaWidth = aState.mAvailSize.width - mRect.width; - } - - // Setup initial list ordinal value - nsIAtom* tag = mContent->GetTag(); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - nsHTMLValue value; - if (eContentAttr_HasValue == - ((nsIHTMLContent*)mContent)->GetAttribute(nsHTMLAtoms::start, value)) { - if (eHTMLUnit_Integer == value.GetUnit()) { - aState.mNextListOrdinal = value.GetIntValue(); - } - } - } - NS_RELEASE(tag); - - // Setup list flags in block reflow state if this block is a list - // item. - const nsStyleDisplay* myDisplay = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_LIST_ITEM == myDisplay->mDisplay) { - const nsStyleList* myList = (const nsStyleList*) - mStyleContext->GetStyleData(eStyleStruct_List); - if (NS_STYLE_LIST_STYLE_POSITION_OUTSIDE == myList->mListStylePosition) { - aState.mListPositionOutside = PR_TRUE; - } - } - - return rv; -} - -PRBool -nsBlockFrame::MoreToReflow(nsBlockReflowState& aState) -{ - PRBool rv = PR_FALSE; - if (NextChildOffset() < mContent->ChildCount()) { - rv = PR_TRUE; - } - return rv; -} - -nsBlockReflowState* -nsBlockFrame::FindBlockReflowState(nsIPresContext* aPresContext, - nsIFrame* aFrame) -{ - nsBlockReflowState* state = nsnull; - if (nsnull != aFrame) { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - while (nsnull != parent) { - nsBlockFrame* block; - nsresult rv = parent->QueryInterface(kBlockFrameCID, (void**) &block); - if (NS_OK == rv) { - nsIPresShell* shell = aPresContext->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(block); - NS_RELEASE(shell); - break; - } - parent->GetGeometricParent(parent); - } - } - return state; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::ContentAppended(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - return nsHTMLContainerFrame::ContentAppended(aShell, aPresContext, aContainer); -} - -NS_METHOD -nsBlockFrame::ContentInserted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - return nsHTMLContainerFrame::ContentInserted(aShell, aPresContext, aContainer, - aChild, aIndexInParent); -} - -NS_METHOD -nsBlockFrame::ContentReplaced(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -NS_METHOD -nsBlockFrame::ContentDeleted(nsIPresShell* aShell, - nsIPresContext* aPresContext, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInParent) -{ - nsresult rv = NS_OK; - return rv; -} - -// XXX if there is nothing special going on here, then remove this -// implementation and let nsFrame do it. -NS_METHOD -nsBlockFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nsresult rv = NS_OK; - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - return rv; -} - -//---------------------------------------------------------------------- - -NS_METHOD -nsBlockFrame::Reflow(nsIPresContext* aPresContext, - nsISpaceManager* aSpaceManager, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsRect& aDesiredRect, - nsReflowStatus& aStatus) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PreReflowCheck(); - } -#endif - - nsBlockReflowState state; - nsresult rv = NS_OK; - - if (eReflowReason_Initial == aReflowState.reason) { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 == (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 != (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - else { -//XXX remove this code and uncomment the assertion when the table code plays nice -#ifdef NS_DEBUG - if (0 != (NS_FRAME_FIRST_REFLOW & mState)) { - printf("XXX: table code isn't setting the reflow reason properly! [nsBlockFrame.cpp]\n"); - } -#endif -//XXX NS_ASSERTION(0 == (NS_FRAME_FIRST_REFLOW & mState), "bad mState"); - } - - aStatus = NS_FRAME_COMPLETE; - rv = InitializeState(aPresContext, aSpaceManager, aReflowState, - aDesiredSize.maxElementSize, state); - - NS_FRAME_TRACE_MSG(("enter nsBlockFrame::Reflow: reason=%d deltaWidth=%d", - aReflowState.reason, state.mDeltaWidth)); - - if (eReflowReason_Incremental == aReflowState.reason) { - nsIPresShell* shell = state.mPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Is the reflow command target at us? - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this == target) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - if (nsIReflowCommand::FrameAppended == type) { - nsLineData* lastLine = LastLine(); - - // Restore the state - if (nsnull != lastLine) { - state.RecoverState(lastLine); - } - - // Reflow unmapped children - PRInt32 kidIndex = NextChildOffset(); - PRInt32 contentChildCount = mContent->ChildCount(); - if (kidIndex == contentChildCount) { - // There is nothing to do here - if (nsnull != lastLine) { - state.mY = lastLine->mBounds.YMost(); - } - } - else { - rv = ReflowUnmapped(state); - } - } else { - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - } - } else { - // The command is passing through us. Get the next frame in the - // reflow chain - nsIFrame* nextFrame; - aReflowState.reflowCommand->GetNext(nextFrame); - - // Restore our state as if nextFrame is the next frame to reflow - nsLineData* line = FindLine(nextFrame); - state.RecoverState(line); - - // Get some available space to start reflowing with - GetAvailableSpace(state, state.mY); - - // Reflow the affected line - nsLineLayout lineLayout(state); - - state.mCurrentLine = &lineLayout; - lineLayout.Initialize(state, line); - - // Have the line handle the incremental reflow - nsRect oldBounds = line->mBounds; - rv = lineLayout.IncrementalReflowFromChild(aReflowState.reflowCommand, - nextFrame); - - // Now place the line. It's possible it won't fit - rv = PlaceLine(state, lineLayout, line); - // XXX The way NS_LINE_LAYOUT_COMPLETE is being used is very confusing... - if (NS_LINE_LAYOUT_COMPLETE == rv) { - mLastContentOffset = line->mLastContentOffset; - mLastContentIsComplete = PRBool(line->mLastContentIsComplete); - state.mPrevKidFrame = lineLayout.mState.mPrevKidFrame; - - // Now figure out what to do with the frames that follow - rv = IncrementalReflowAfter(state, line, rv, oldBounds); - } - } - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } else { - nsresult rv = NS_OK; - nsIPresShell* shell = aPresContext->GetShell(); - shell->PutCachedData(this, &state); - - // Check for an overflow list - DrainOverflowList(); - - if (nsnull != mLines) { - rv = ReflowMapped(state); - } - - if (NS_OK == rv) { - if ((nsnull != mLines) && (state.mAvailSize.height <= 0)) { - // We are out of space - } - if (MoreToReflow(state)) { - rv = ReflowUnmapped(state); - } - } - -#ifdef NS_DEBUG - if (0 != mContent->ChildCount()) { - NS_ASSERTION(nsnull != mLines, "reflowed zero children"); - } -#endif - - // Return our desired rect - ComputeDesiredRect(state, aReflowState.maxSize, aDesiredRect); - - // Set return status - aStatus = NS_FRAME_COMPLETE; - if (NS_LINE_LAYOUT_NOT_COMPLETE == rv) { - rv = NS_OK; - aStatus = NS_FRAME_NOT_COMPLETE; - } - - // Now that reflow has finished, remove the cached pointer - shell->RemoveCachedData(this); - NS_RELEASE(shell); - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLines(PR_TRUE); - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_TRACE_MSG( - ("exit nsBlockFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredRect.width, aDesiredRect.height)); - return rv; -} - -nsLineData* nsBlockFrame::FindLine(nsIFrame* aFrame) -{ - // Find the line that contains the aFrame - nsLineData* line = mLines; - while (nsnull != line) { - nsIFrame* child = line->mFirstChild; - for (PRInt32 count = line->mChildCount; count > 0; count--) { - if (child == aFrame) { - return line; - } - - child->GetNextSibling(child); - } - - // Move to the next line - line = line->mNextLine; - } - - return nsnull; -} - -nsLineData* nsBlockFrame::LastLine() -{ - nsLineData* lastLine = mLines; - - // Get the last line - if (nsnull != lastLine) { - while (nsnull != lastLine->mNextLine) { - lastLine = lastLine->mNextLine; - } - } - - return lastLine; -} - -nsresult nsBlockFrame::IncrementalReflowAfter(nsBlockReflowState& aState, - nsLineData* aLine, - nsresult aReflowStatus, - const nsRect& aOldBounds) -{ - // Now just reflow all the lines that follow... - // XXX Obviously this needs to be more efficient - return ReflowMappedFrom(aState, aLine->mNextLine); -} - -void nsBlockFrame::ComputeDesiredRect(nsBlockReflowState& aState, - const nsSize& aMaxSize, - nsRect& aDesiredRect) -{ - aDesiredRect.x = 0; - aDesiredRect.y = 0; - - // Special check for zero sized content: If our content is zero - // sized then we collapse into nothingness. - if ((0 == aState.mKidXMost - aState.mBorderPadding.left) && - (0 == aState.mY - aState.mBorderPadding.top)) { - aDesiredRect.width = 0; - aDesiredRect.height = 0; - } - else { - aDesiredRect.width = aState.mKidXMost + aState.mBorderPadding.right; - if (!aState.mUnconstrainedWidth) { - // Make sure we're at least as wide as the max size we were given - nscoord maxWidth = aState.mAvailSize.width + aState.mBorderPadding.left + - aState.mBorderPadding.right; - if (aDesiredRect.width < maxWidth) { - aDesiredRect.width = maxWidth; - } - } - aState.mY += aState.mBorderPadding.bottom; - nscoord lastBottomMargin = aState.mPrevPosBottomMargin - - aState.mPrevNegBottomMargin; - if (!aState.mUnconstrainedHeight && (lastBottomMargin > 0)) { - // It's possible that we don't have room for the last bottom - // margin (the last bottom margin is the margin following a block - // element that we contain; it isn't applied immediately because - // of the margin collapsing logic). This can happen when we are - // reflowed in a limited amount of space because we don't know in - // advance what the last bottom margin will be. - nscoord maxY = aMaxSize.height; - if (aState.mY + lastBottomMargin > maxY) { - lastBottomMargin = maxY - aState.mY; - if (lastBottomMargin < 0) { - lastBottomMargin = 0; - } - } - } - aState.mY += lastBottomMargin; - aDesiredRect.height = aState.mY; - - if (!aState.mBlockIsPseudo) { - // Clamp the desired rect height when style height applies - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredRect.height = aState.mBorderPadding.top + - aState.mStyleSize.height + aState.mBorderPadding.bottom; - } - } - } -} - -//---------------------------------------------------------------------- - -void nsBlockFrame::ReflowFloater(nsIPresContext* aPresContext, - nsBlockReflowState& aState, - nsIFrame* aFloaterFrame) -{ - // Compute the available space for the floater. Use the default - // 'auto' width and height values - nsSize kidAvailSize(0, NS_UNCONSTRAINEDSIZE); - nsSize styleSize; - PRIntn styleSizeFlags = nsCSSLayout::GetStyleSize(aPresContext, *aState.reflowState, - styleSize); - - // XXX The width and height are for the content area only. Add in space for - // border and padding - if (styleSizeFlags & NS_SIZE_HAS_WIDTH) { - kidAvailSize.width = styleSize.width; - } - if (styleSizeFlags & NS_SIZE_HAS_HEIGHT) { - kidAvailSize.height = styleSize.height; - } - - // Resize reflow the anchored item into the available space - // XXX Check for complete? - nsReflowMetrics desiredSize(nsnull); - nsReflowState reflowState(aFloaterFrame, *aState.reflowState, kidAvailSize, - eReflowReason_Initial); - nsReflowStatus status; - - aFloaterFrame->WillReflow(*aPresContext); - aFloaterFrame->Reflow(aPresContext, desiredSize, reflowState, status); - aFloaterFrame->SizeTo(desiredSize.width, desiredSize.height); - - aFloaterFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); -} - -PRBool -nsBlockFrame::AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - - if (nsnull != state) { - // Get the frame associated with the space manager, and get its - // nsIAnchoredItems interface - nsIFrame* frame = state->mSpaceManager->GetFrame(); - nsIAnchoredItems* anchoredItems = nsnull; - - frame->QueryInterface(kIAnchoredItemsIID, (void**)&anchoredItems); - NS_ASSERTION(nsnull != anchoredItems, "no anchored items interface"); - if (nsnull != anchoredItems) { - anchoredItems->AddAnchoredItem(aFloater, - nsIAnchoredItems::anHTMLFloater, - this); - - // Reflow the floater - ReflowFloater(aPresContext, *state, aFloater); - - // Determine whether we place it at the top or we place it below the - // current line - if (IsLeftMostChild(aPlaceholder)) { - if (nsnull == mRunInFloaters) { - mRunInFloaters = new nsVoidArray; - } - mRunInFloaters->AppendElement(aPlaceholder); - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } else { - // Add the placeholder to our to-do list - state->mPendingFloaters.AppendElement(aPlaceholder); - } - return PR_TRUE; - } - } - - return PR_FALSE; -} - -// XXX Deprecated -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) -{ -#if 0 - nsIPresShell* shell = aPresContext->GetShell(); - nsBlockReflowState* state = (nsBlockReflowState*) shell->GetCachedData(this); - NS_RELEASE(shell); - if (nsnull != state) { - PlaceFloater(aPresContext, aFloater, aPlaceholder, *state); - } -#endif -} - -PRBool -nsBlockFrame::IsLeftMostChild(nsIFrame* aFrame) -{ - do { - nsIFrame* parent; - aFrame->GetGeometricParent(parent); - - // See if there are any non-zero sized child frames that precede - // aFrame in the child list - nsIFrame* child; - parent->FirstChild(child); - while ((nsnull != child) && (aFrame != child)) { - nsSize size; - - // Is the child zero-sized? - child->GetSize(size); - if ((size.width > 0) || (size.height > 0)) { - // We found a non-zero sized child frame that precedes aFrame - return PR_FALSE; - } - child->GetNextSibling(child); - } - - // aFrame is the left-most non-zero sized frame in its geometric parent. - // Walk up one level and check that its parent is left-most as well - aFrame = parent; - } while (aFrame != this); - return PR_TRUE; -} - -// Used when placing run-in floaters (floaters displayed at the top of the -// block as supposed to below the current line) -void -nsBlockFrame::PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder, - nsBlockReflowState& aState) -{ - nsISpaceManager* sm = aState.mSpaceManager; - - // Get the type of floater - const nsStyleDisplay* floaterDisplay; - aFloater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)floaterDisplay); - - // Commit some space in the space manager, and adjust our current - // band of available space. - nsRect region; - aFloater->GetRect(region); - region.y = aState.mY; - if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) { - region.x = aState.mX; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats, - "bad float type"); - region.x = aState.mCurrentBand.availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - sm->AddRectRegion(aFloater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - aFloater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - - // Update the band of available space to reflect space taken up by - // the floater - GetAvailableSpace(aState, aState.mY); - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -// XXX It's unclear what coordinate space aY is in. Is it relative to the -// upper-left origin of the containing block, or relative to aState.mY? -void -nsBlockFrame::PlaceBelowCurrentLineFloaters(nsBlockReflowState& aState, - nsVoidArray* aFloaterList, - nscoord aY) -{ - NS_PRECONDITION(aFloaterList->Count() > 0, "no floaters"); - - nsISpaceManager* sm = aState.mSpaceManager; - nsBlockBandData* bd = &aState.mCurrentBand; - - // XXX Factor this code with PlaceFloater()... - PRInt32 numFloaters = aFloaterList->Count(); - for (PRInt32 i = 0; i < numFloaters; i++) { - nsPlaceholderFrame* placeholderFrame = (nsPlaceholderFrame*)aFloaterList->ElementAt(i); - nsIFrame* floater = placeholderFrame->GetAnchoredItem(); - nsRect region; - - // Get the band of available space - // XXX This is inefficient to do this inside the loop... - GetAvailableSpace(aState, aY); - - // Get the type of floater - const nsStyleDisplay* sd; - floater->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)sd); - - floater->GetRect(region); - // XXX GetAvailableSpace() is translating availSpace by aState.mY... - region.y = bd->availSpace.y - aState.mY; - if (NS_STYLE_FLOAT_LEFT == sd->mFloats) { - region.x = bd->availSpace.x; - } else { - NS_ASSERTION(NS_STYLE_FLOAT_RIGHT == sd->mFloats, "bad float type"); - region.x = bd->availSpace.XMost() - region.width; - } - - // XXX Don't forget the floater's margins... - sm->Translate(aState.mBorderPadding.left, 0); - // XXX Temporary incremental hack - sm->RemoveRegion(floater); - sm->AddRectRegion(floater, region); - - // Set the origin of the floater in world coordinates - nscoord worldX, worldY; - sm->GetTranslation(worldX, worldY); - floater->MoveTo(region.x + worldX, region.y + worldY); - sm->Translate(-aState.mBorderPadding.left, 0); - } - - // Pass on updated available space to the current line - if (nsnull != aState.mCurrentLine) { - nsLineLayout& lineLayout = *aState.mCurrentLine; - GetAvailableSpace(aState, aY); - lineLayout.SetReflowSpace(aState.mCurrentBand.availSpace); - } -} - -//---------------------------------------------------------------------- - -nsLineData* -nsBlockFrame::GetFirstLine() -{ - return mLines; -} - -PRIntn -nsBlockFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_TOP; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_BOTTOM; - } - return skip; -} diff --git a/mozilla/layout/html/base/src/nsBodyFrame.cpp b/mozilla/layout/html/base/src/nsBodyFrame.cpp index 64b40cba17a..a5d4b7d306b 100644 --- a/mozilla/layout/html/base/src/nsBodyFrame.cpp +++ b/mozilla/layout/html/base/src/nsBodyFrame.cpp @@ -18,7 +18,6 @@ #include "nsBodyFrame.h" #include "nsIContent.h" #include "nsIContentDelegate.h" -#include "nsBlockFrame.h" #include "nsIReflowCommand.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" @@ -26,12 +25,11 @@ #include "nsIPresShell.h" #include "nsIViewManager.h" #include "nsIDeviceContext.h" -#include "nsBlockFrame.h" +#include "nsIRunaround.h" #include "nsSpaceManager.h" #include "nsHTMLAtoms.h" - -static NS_DEFINE_IID(kIRunaroundIID, NS_IRUNAROUND_IID); -static NS_DEFINE_IID(kIAnchoredItemsIID, NS_IANCHOREDITEMS_IID); +#include "nsHTMLIIDs.h" +#include "nsCSSBlockFrame.h" nsresult nsBodyFrame::NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, @@ -78,27 +76,28 @@ nsBodyFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) void nsBodyFrame::CreateColumnFrame(nsIPresContext* aPresContext) { + nsIStyleContext* styleContext = + aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo, this); + // Do we have a prev-in-flow? if (nsnull == mPrevInFlow) { // No, create a column pseudo frame - nsBlockFrame::NewFrame(&mFirstChild, mContent, this); + NS_NewCSSBlockFrame(&mFirstChild, mContent, this); mChildCount = 1; - - // Resolve style and set the style context - nsIStyleContext* styleContext = - aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo, this); mFirstChild->SetStyleContext(aPresContext,styleContext); - NS_RELEASE(styleContext); } else { - nsBodyFrame* prevBody = (nsBodyFrame*)mPrevInFlow; - - nsIFrame* prevColumn = prevBody->mFirstChild; - NS_ASSERTION(prevBody->ChildIsPseudoFrame(prevColumn), "bad previous column"); - // Create a continuing column - prevColumn->CreateContinuingFrame(aPresContext, this, nsnull, mFirstChild); + nsBodyFrame* prevBody = (nsBodyFrame*)mPrevInFlow; + nsIFrame* prevColumn = prevBody->mFirstChild; + NS_ASSERTION(prevBody->ChildIsPseudoFrame(prevColumn), + "bad previous column"); + + prevColumn->CreateContinuingFrame(aPresContext, this, styleContext, + mFirstChild); mChildCount = 1; } + + NS_RELEASE(styleContext); } nsSize nsBodyFrame::GetColumnAvailSpace(nsIPresContext* aPresContext, @@ -240,11 +239,15 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext* aPresContext, mFirstChild->SetRect(desiredRect); mFirstChild->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); +#if XXX + // the block knows to PropagateContentOffsets so this isn't necessary + // Set our last content offset and whether the last content is complete // based on the state of the pseudo frame - nsBlockFrame* blockPseudoFrame = (nsBlockFrame*)mFirstChild; + nsCSSBlockFrame* blockPseudoFrame = (nsCSSBlockFrame*)mFirstChild; mLastContentOffset = blockPseudoFrame->GetLastContentOffset(); mLastContentIsComplete = blockPseudoFrame->GetLastContentIsComplete(); +#endif // Return our desired size ComputeDesiredSize(desiredRect, aReflowState.maxSize, borderPadding, aDesiredSize); @@ -260,7 +263,8 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext* aPresContext, } } - NS_FRAME_TRACE_MSG(("exit nsBodyFrame::Reflow: status=%d width=%d height=%d", + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("exit nsBodyFrame::Reflow: status=%d width=%d height=%d", aStatus, aDesiredSize.width, aDesiredSize.height)); return NS_OK; } diff --git a/mozilla/layout/html/base/src/nsHTMLBullet.cpp b/mozilla/layout/html/base/src/nsHTMLBullet.cpp index 5666a8a6fc5..8578ffb12f8 100644 --- a/mozilla/layout/html/base/src/nsHTMLBullet.cpp +++ b/mozilla/layout/html/base/src/nsHTMLBullet.cpp @@ -18,7 +18,9 @@ #include "nsHTMLParts.h" #include "nsHTMLTagContent.h" #include "nsLeafFrame.h" -#include "nsBlockFrame.h" +#include "nsCSSBlockFrame.h" +#include "nsIInlineReflow.h" +#include "nsCSSLineLayout.h" #include "nsIPresContext.h" #include "nsIPresShell.h" #include "nsIRenderingContext.h" @@ -32,6 +34,21 @@ #include "nsHTMLBase.h" #include "nsIView.h" +// XXX eliminate the bullet numbering hackery: + +// 1) use a dependency graph of some sort that is updated when LI's +// come and go in the content model (how do we invalidate it when a +// content change occurs?): maybe for block's that are display: +// list-item, they keep a side data structure that is the ordinal data +// for it's children LI's? + +// 2) Alternatively, have the LI's number themselves automatically and +// use a GetAttribute on the content to discover the correct number (N^2) + +// XXX Also eliminate the way that we find the +// nsCSSBlockReflowState!!! It's bogus beyond belief! An ISA +// QueryInterface on the reflow-state should do the trick. + class Bullet : public nsHTMLTagContent { public: Bullet(); @@ -49,40 +66,45 @@ public: nsIFrame*& aResult); }; -class BulletFrame : public nsLeafFrame { +class BulletFrame : public nsFrame, nsIInlineReflow { public: BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame); virtual ~BulletFrame(); - NS_IMETHOD DeleteFrame(); + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + // nsIFrame + NS_IMETHOD DeleteFrame(); NS_IMETHOD Paint(nsIPresContext &aCX, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - - NS_IMETHOD Reflow(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); - NS_IMETHOD List(FILE* out, PRInt32 aIndent) const; + // nsIInlineReflow + NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout); + NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState); + protected: - virtual void GetDesiredSize(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, - nsReflowMetrics& aDesiredSize); + void GetDesiredSize(nsIPresContext* aPresContext, + nsCSSBlockReflowState* aBlockState, + const nsReflowState& aReflowState, + nsReflowMetrics& aMetrics); - /** - * Return the reflow state for the list container that contains this - * list item frame. There may be no list container (a dangling LI) - * therefore this may return nsnull. - */ - nsBlockReflowState* GetListContainerReflowState(nsIPresContext* aCX); + PRInt32 GetListItemOrdinal(nsIPresContext* aCX, + nsCSSBlockReflowState* aBlockState, + const nsStyleList& aMol); - PRInt32 GetListItemOrdinal(nsIPresContext* aCX, const nsStyleList& aMol); + void GetListItemText(nsIPresContext* aCX, + nsCSSBlockReflowState* aBlockState, + const nsStyleList& aMol, + nsString& aResult); - void GetListItemText(nsIPresContext* aCX, nsString& aResult, - const nsStyleList& aMol); + nsCSSBlockReflowState* + GetListContainerReflowState(nsIPresContext* aCX, + const nsReflowState& aReflowState); PRPackedBool mOrdinalValid; PRInt32 mOrdinal; @@ -148,7 +170,7 @@ NS_NewHTMLBullet(nsIHTMLContent** aInstancePtrResult) //---------------------------------------------------------------------- BulletFrame::BulletFrame(nsIContent* aContent, nsIFrame* aParentFrame) - : nsLeafFrame(aContent, aParentFrame) + : nsFrame(aContent, aParentFrame) { } @@ -156,12 +178,26 @@ BulletFrame::~BulletFrame() { } +NS_IMETHODIMP +BulletFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIInlineReflowIID)) { + *aInstancePtrResult = (void*) ((nsIInlineReflow*)this); + return NS_OK; + } + return nsFrame::QueryInterface(aIID, aInstancePtrResult); +} + NS_METHOD BulletFrame::DeleteFrame() { // Release image loader first so that it's refcnt can go to zero mImageLoader.DestroyLoader(); - return nsLeafFrame::DeleteFrame(); + return nsFrame::DeleteFrame(); } NS_METHOD @@ -255,7 +291,7 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_LOWER_ALPHA: case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); - GetListItemText(&aCX, text, *myList); + GetListItemText(&aCX, nsnull, *myList, text); aRenderingContext.SetFont(myFont->mFont); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, fm->GetWidth(text)); @@ -266,73 +302,37 @@ BulletFrame::Paint(nsIPresContext& aCX, return NS_OK; } -NS_METHOD -BulletFrame::Reflow(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - GetDesiredSize(aCX, aReflowState, aDesiredSize); - if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; - } - - // Get cached state for containing block frame - nsBlockReflowState* state = - nsBlockFrame::FindBlockReflowState(aCX, this); - if (nsnull != state) { - nsLineLayout* lineLayoutState = state->mCurrentLine; - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = - NS_LINE_LAYOUT_REFLOW_RESULT_AWARE; - } - } - - aStatus = NS_FRAME_COMPLETE; - return NS_OK; -} +// XXX This is a hack to discover the block container that is keeping +// track of our list item ordinal value // Return the reflow state for the list container that contains this // list item frame. There may be no list container (a dangling LI) // therefore this may return nsnull. -nsBlockReflowState* -BulletFrame::GetListContainerReflowState(nsIPresContext* aCX) +nsCSSBlockReflowState* +BulletFrame::GetListContainerReflowState(nsIPresContext* aCX, + const nsReflowState& aReflowState) { - nsBlockReflowState* state = nsnull; - nsIFrame* parent = mGeometricParent; - while (nsnull != parent) { - void* ft; - nsresult status = parent->QueryInterface(kBlockFrameCID, &ft); - if (NS_OK == status) { - // The parent is a block. See if its content object is a list - // container. Only UL, OL, MENU or DIR can be list containers. - // XXX need something more flexible, say style? - nsIContent* parentContent; - - parent->GetContent(parentContent); - nsIAtom* tag = parentContent->GetTag(); - NS_RELEASE(parentContent); - if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || - (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { - NS_RELEASE(tag); - break; - } + const nsReflowState* rs = aReflowState.parentReflowState; + while (nsnull != rs) { + nsIContent* content; + rs->frame->GetContent(content); + nsIAtom* tag = content->GetTag(); + NS_RELEASE(content); + if ((tag == nsHTMLAtoms::ul) || (tag == nsHTMLAtoms::ol) || + (tag == nsHTMLAtoms::menu) || (tag == nsHTMLAtoms::dir)) { NS_RELEASE(tag); + return (nsCSSBlockReflowState*) rs; } - parent->GetGeometricParent(parent); + NS_RELEASE(tag); + rs = rs->parentReflowState; } - if (nsnull != parent) { - nsIPresShell* shell = aCX->GetShell(); - state = (nsBlockReflowState*) shell->GetCachedData(parent); - NS_RELEASE(shell); - } - return state; + return nsnull; } PRInt32 -BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, - const nsStyleList& aListStyle) +BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, + nsCSSBlockReflowState* aReflowState, + const nsStyleList& aListStyle) { if (mOrdinalValid) { return mOrdinal; @@ -340,9 +340,6 @@ BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, PRInt32 ordinal = 0; - // Get block reflow state for the list container - nsBlockReflowState* state = GetListContainerReflowState(aCX); - // Try to get value directly from the list-item, if it specifies a // value attribute. We do this with our parent's content. nsHTMLValue value; @@ -352,8 +349,8 @@ BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, if (eContentAttr_HasValue == html->GetAttribute(nsHTMLAtoms::value, value)) { if (eHTMLUnit_Integer == value.GetUnit()) { ordinal = value.GetIntValue(); - if (nsnull != state) { - state->mNextListOrdinal = ordinal + 1; + if (nsnull != aReflowState) { + aReflowState->mNextListOrdinal = ordinal + 1; } NS_RELEASE(html); goto done; @@ -362,8 +359,8 @@ BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, NS_RELEASE(html); // Get ordinal from block reflow state - if (nsnull != state) { - ordinal = state->mNextListOrdinal; + if (nsnull != aReflowState) { + ordinal = aReflowState->mNextListOrdinal; if (ordinal < 0) { // This is the first list item and the list container doesn't // have a "start" attribute. Get the starting ordinal value @@ -379,7 +376,7 @@ BulletFrame::GetListItemOrdinal(nsIPresContext* aCX, break; } } - state->mNextListOrdinal = ordinal + 1; + aReflowState->mNextListOrdinal = ordinal + 1; } done: @@ -395,12 +392,15 @@ static const char* gUpperRomanCharsB = "VLD?"; static const char* gLowerAlphaChars = "abcdefghijklmnopqrstuvwxyz"; static const char* gUpperAlphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +// XXX change roman/alpha to use unsigned math so that maxint and +// maxnegint will work void BulletFrame::GetListItemText(nsIPresContext* aCX, - nsString& result, - const nsStyleList& aListStyle) + nsCSSBlockReflowState* aReflowState, + const nsStyleList& aListStyle, + nsString& result) { - PRInt32 ordinal = GetListItemOrdinal(aCX, aListStyle); + PRInt32 ordinal = GetListItemOrdinal(aCX, aReflowState, aListStyle); char cbuf[40]; switch (aListStyle.mListStyleType) { case NS_STYLE_LIST_STYLE_DECIMAL: @@ -411,7 +411,9 @@ BulletFrame::GetListItemText(nsIPresContext* aCX, case NS_STYLE_LIST_STYLE_LOWER_ROMAN: case NS_STYLE_LIST_STYLE_UPPER_ROMAN: { - // XXX deal with an ordinal of ZERO + if (0 == ordinal) { + ordinal = 1; + } nsAutoString addOn; nsAutoString decStr; decStr.Append(ordinal, 10); @@ -512,23 +514,23 @@ BulletFrame::GetListItemText(nsIPresContext* aCX, result.Append("."); } -// from laytext.c -#define MIN_BULLET_SIZE 5 +#define MIN_BULLET_SIZE 5 // from laytext.c void BulletFrame::GetDesiredSize(nsIPresContext* aCX, + nsCSSBlockReflowState* aState, const nsReflowState& aReflowState, - nsReflowMetrics& aDesiredSize) + nsReflowMetrics& aMetrics) { const nsStyleList* myList = (const nsStyleList*)mStyleContext->GetStyleData(eStyleStruct_List); if (myList->mListStyleImage.Length() > 0) { mImageLoader.SetURL(myList->mListStyleImage); - mImageLoader.GetDesiredSize(aCX, aReflowState, aDesiredSize); + mImageLoader.GetDesiredSize(aCX, aReflowState, aMetrics); if (!mImageLoader.GetLoadImageFailed()) { nsHTMLBase::CreateViewForFrame(aCX, this, mStyleContext, PR_FALSE); - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; + aMetrics.ascent = aMetrics.height; + aMetrics.descent = 0; return; } } @@ -543,10 +545,10 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, nsAutoString text; switch (myList->mListStyleType) { case NS_STYLE_LIST_STYLE_NONE: - aDesiredSize.width = 0; - aDesiredSize.height = 0; - aDesiredSize.ascent = 0; - aDesiredSize.descent = 0; + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; break; default: @@ -565,10 +567,10 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) { mPadding.right = bulletSize / 2; } - aDesiredSize.width = mPadding.right + bulletSize; - aDesiredSize.height = mPadding.bottom + bulletSize; - aDesiredSize.ascent = mPadding.bottom + bulletSize; - aDesiredSize.descent = 0; + aMetrics.width = mPadding.right + bulletSize; + aMetrics.height = mPadding.bottom + bulletSize; + aMetrics.ascent = mPadding.bottom + bulletSize; + aMetrics.descent = 0; break; case NS_STYLE_LIST_STYLE_DECIMAL: @@ -576,17 +578,53 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, case NS_STYLE_LIST_STYLE_UPPER_ROMAN: case NS_STYLE_LIST_STYLE_LOWER_ALPHA: case NS_STYLE_LIST_STYLE_UPPER_ALPHA: - GetListItemText(aCX, text, *myList); + GetListItemText(aCX, aState, *myList, text); if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == myList->mListStylePosition) { // Inside bullets need some extra width to get the padding // between the list item and the content that follows. mPadding.right = fm->GetHeight() / 2; // From old layout engine } - aDesiredSize.width = mPadding.right + fm->GetWidth(text); - aDesiredSize.height = fm->GetHeight(); - aDesiredSize.ascent = fm->GetMaxAscent(); - aDesiredSize.descent = fm->GetMaxDescent(); + aMetrics.width = mPadding.right + fm->GetWidth(text); + aMetrics.height = fm->GetHeight(); + aMetrics.ascent = fm->GetMaxAscent(); + aMetrics.descent = fm->GetMaxDescent(); break; } NS_RELEASE(fm); } + +NS_IMETHODIMP +BulletFrame::InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState) +{ + nsCSSBlockReflowState* state = + GetListContainerReflowState(aLineLayout.mPresContext, aReflowState); + + // Get the base size + GetDesiredSize(aLineLayout.mPresContext, state, aReflowState, aMetrics); + + // Add in the border and padding; split the top/bottom between the + // ascent and descent to make things look nice + const nsStyleSpacing* space =(const nsStyleSpacing*) + mStyleContext->GetStyleData(eStyleStruct_Spacing); + nsMargin borderPadding; + space->CalcBorderPaddingFor(this, borderPadding); + aMetrics.width += borderPadding.left + borderPadding.right; + aMetrics.height += borderPadding.top + borderPadding.bottom; + aMetrics.ascent += borderPadding.top; + aMetrics.descent += borderPadding.bottom; + + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = aMetrics.width; + aMetrics.maxElementSize->height = aMetrics.height; + } + return NS_INLINE_REFLOW_COMPLETE; +} + +NS_IMETHODIMP +BulletFrame::FindTextRuns(nsCSSLineLayout& aLineLayout) +{ + aLineLayout.EndTextRun(); + return NS_OK; +} diff --git a/mozilla/layout/html/base/src/nsHTMLContainer.cpp b/mozilla/layout/html/base/src/nsHTMLContainer.cpp index f5dd7838a2a..90ea819c102 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainer.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainer.cpp @@ -22,8 +22,7 @@ #include "nsIArena.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" -#include "nsBlockFrame.h" -#include "nsInlineFrame.h" +#include "nsCSSBlockFrame.h" #include "nsIPresContext.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" @@ -34,6 +33,8 @@ #include "prprf.h" #include "nsISizeOfHandler.h" +#include "nsCSSInlineFrame.h" + nsresult NS_NewHTMLContainer(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag) @@ -230,11 +231,11 @@ nsHTMLContainer::CreateFrame(nsIPresContext* aPresContext, switch (styleDisplay->mDisplay) { case NS_STYLE_DISPLAY_BLOCK: case NS_STYLE_DISPLAY_LIST_ITEM: - rv = nsBlockFrame::NewFrame(&frame, this, aParentFrame); + rv = NS_NewCSSBlockFrame(&frame, this, aParentFrame); break; case NS_STYLE_DISPLAY_INLINE: - rv = nsInlineFrame::NewFrame(&frame, this, aParentFrame); + rv = NS_NewCSSInlineFrame(&frame, this, aParentFrame); break; default: diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp index 12ea5df79c8..7905c8f03a0 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.cpp @@ -207,62 +207,6 @@ static void AdjustIndexInParents(nsIFrame* aContainerFrame, } } -nsresult -nsHTMLContainerFrame::CreateFrameFor(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIStyleContext* aStyleContext, - nsIFrame*& aResult) -{ - // Get the style data for the frame - const nsStylePosition* position = (const nsStylePosition*) - aStyleContext->GetStyleData(eStyleStruct_Position); - const nsStyleDisplay* display = (const nsStyleDisplay*) - aStyleContext->GetStyleData(eStyleStruct_Display); - nsIFrame* frame = nsnull; - - // See whether it wants any special handling - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == position->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if (display->mFloats != NS_STYLE_FLOAT_NONE) { - rv = nsPlaceholderFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if ((NS_STYLE_OVERFLOW_SCROLL == display->mOverflow) || - (NS_STYLE_OVERFLOW_AUTO == display->mOverflow)) { - rv = NS_NewScrollFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else if (NS_STYLE_DISPLAY_NONE == display->mDisplay) { - rv = nsFrame::NewFrame(&frame, aContent, this); - if (NS_OK == rv) { - frame->SetStyleContext(aPresContext, aStyleContext); - } - } - else { - // Ask the content delegate to create the frame - nsIContentDelegate* delegate = aContent->GetDelegate(aPresContext); - rv = delegate->CreateFrame(aPresContext, aContent, this, - aStyleContext, frame); - NS_RELEASE(delegate); - } - if (NS_OK == rv) { - // Wrap the frame in a view if necessary - rv = nsHTMLBase::CreateViewForFrame(aPresContext, frame, aStyleContext, - PR_FALSE); - } - aResult = frame; - return rv; -} - NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, @@ -321,7 +265,8 @@ NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsIStyleContext* kidSC; kidSC = aPresContext->ResolveStyleContextFor(aChild, parent); nsIFrame* newFrame; - nsresult rv = parent->CreateFrameFor(aPresContext, aChild, kidSC, newFrame); +//XXX nsresult rv = parent->CreateFrameFor(aPresContext, aChild, kidSC, newFrame); + nsresult rv = nsHTMLBase::CreateFrame(aPresContext, this, aChild, nsnull, newFrame); if (NS_OK != rv) { return rv; } @@ -369,23 +314,25 @@ NS_METHOD nsHTMLContainerFrame::ContentInserted(nsIPresShell* aShell, nsresult nsHTMLContainerFrame::ProcessInitialReflow(nsIPresContext* aPresContext) { - const nsStyleDisplay* display = (const nsStyleDisplay*) - mStyleContext->GetStyleData(eStyleStruct_Display); - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsHTMLContainerFrame::ProcessInitialReflow: display=%d", - display->mDisplay)); - if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { - // This container is a list-item container. Therefore it needs a - // bullet content object. - nsIHTMLContent* bullet; - nsresult rv = NS_NewHTMLBullet(&bullet); - if (NS_OK != rv) { - return rv; - } + if (nsnull == mPrevInFlow) { + const nsStyleDisplay* display = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, + ("nsHTMLContainerFrame::ProcessInitialReflow: display=%d", + display->mDisplay)); + if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) { + // This container is a list-item container. Therefore it needs a + // bullet content object. + nsIHTMLContent* bullet; + nsresult rv = NS_NewHTMLBullet(&bullet); + if (NS_OK != rv) { + return rv; + } - // Insert the bullet. Do not allow an incremental reflow operation - // to occur. - mContent->InsertChildAt(bullet, 0, PR_FALSE); + // Insert the bullet. Do not allow an incremental reflow operation + // to occur. + mContent->InsertChildAt(bullet, 0, PR_FALSE); + } } return NS_OK; diff --git a/mozilla/layout/html/base/src/nsHTMLContainerFrame.h b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h index aefa2feb007..c7d4a11a232 100644 --- a/mozilla/layout/html/base/src/nsHTMLContainerFrame.h +++ b/mozilla/layout/html/base/src/nsHTMLContainerFrame.h @@ -56,12 +56,8 @@ protected: virtual PRIntn GetSkipSides() const = 0; - nsresult CreateFrameFor(nsIPresContext* aPresContext, - nsIContent* aContent, - nsIStyleContext* aStyleContext, - nsIFrame*& aResult); - nsresult ProcessInitialReflow(nsIPresContext* aPresContext); }; #endif /* nsHTMLContainerFrame_h___ */ + diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.cpp b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp index c80af44dc4a..27d79849233 100644 --- a/mozilla/layout/html/base/src/nsHTMLIIDs.cpp +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.cpp @@ -17,9 +17,15 @@ */ #include "nsHTMLIIDs.h" #include "nsIHTMLContent.h" -#include "nsBlockFrame.h" +#include "nsIAnchoredItems.h" +#include "nsIFloaterContainer.h" +#include "nsIRunaround.h" +#include "nsIInlineReflow.h" +#include "nsCSSBlockFrame.h" +const nsIID kIAnchoredItemsIID = NS_IANCHORED_ITEMS_IID; +const nsIID kIFloaterContainerIID = NS_IFLOATER_CONTAINER_IID; const nsIID kIHTMLContentIID = NS_IHTMLCONTENT_IID; -const nsIID kBlockFrameCID = NS_BLOCKFRAME_CID; -const nsIID kIInlineFrameIID = NS_IINLINE_FRAME_IID; - +const nsIID kIInlineReflowIID = NS_IINLINE_REFLOW_IID; +const nsIID kIRunaroundIID = NS_IRUNAROUND_IID; +const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID; diff --git a/mozilla/layout/html/base/src/nsHTMLIIDs.h b/mozilla/layout/html/base/src/nsHTMLIIDs.h index e9b5f541d92..d59972e1a07 100644 --- a/mozilla/layout/html/base/src/nsHTMLIIDs.h +++ b/mozilla/layout/html/base/src/nsHTMLIIDs.h @@ -20,8 +20,12 @@ #include "nsISupports.h" +extern const nsIID kBlockFrameCID; // XXX temporary + +extern const nsIID kIAnchoredItemsIID; +extern const nsIID kIFloaterContainerIID; extern const nsIID kIHTMLContentIID; -extern const nsIID kBlockFrameCID; -extern const nsIID kIInlineFrameIID; +extern const nsIID kIInlineReflowIID; +extern const nsIID kIRunaroundIID; #endif /* nsHTMLIIDs_h___ */ diff --git a/mozilla/layout/html/base/src/nsIFloaterContainer.h b/mozilla/layout/html/base/src/nsIFloaterContainer.h index 8fbdaf03955..46d5d2aade8 100644 --- a/mozilla/layout/html/base/src/nsIFloaterContainer.h +++ b/mozilla/layout/html/base/src/nsIFloaterContainer.h @@ -18,14 +18,13 @@ #ifndef nsIFloaterContainer_h___ #define nsIFloaterContainer_h___ -#include +#include "nsIFrame.h" class nsPlaceholderFrame; class nsIPresContext; -// IID for the nsIFloaterContainer interface {5A305EE0-CB55-11d1-8556-00A02468FAB6} -#define NS_IFLOATERCONTAINER_IID \ -{ 0x5a305ee0, 0xcb55, 0x11d1, \ - {0x85, 0x56, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} +// 5a305ee0-cb55-11d1-8556-00a02468fab6 +#define NS_IFLOATER_CONTAINER_IID \ + { 0x5a305ee0, 0xcb55, 0x11d1, {0x85, 0x56, 0x0, 0xa0, 0x24, 0x68, 0xfa, 0xb6}} /** * An interface for communicating with the enclosing block-level container @@ -42,22 +41,10 @@ public: * @param aPlaceholder the placeholder frame associated with the floating * element. */ - virtual PRBool AddFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) = 0; - - /** - * Call to place the floating element, because the placeholder frame has been - * reflowed. - * - * XXX This is kind of hokey and unreliable, because it relies on the placeholder - * getting reflowed. That won't necessarily happen if its geometric parent just - * decides to move it... It would probably be better if the implementor of this - * interface managed the tracking of the placeholder within the containing line - **/ - virtual void PlaceFloater(nsIPresContext* aPresContext, - nsIFrame* aFloater, - nsPlaceholderFrame* aPlaceholder) = 0; + virtual PRBool AddFloater(nsIPresContext* aPresContext, + const nsReflowState& aPlaceholderReflowState, + nsIFrame* aFloater, + nsPlaceholderFrame* aPlaceholder) = 0; }; #endif /* nsIFloaterContainer_h___ */ diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp deleted file mode 100644 index 06a623a8d1b..00000000000 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ /dev/null @@ -1,1288 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsInlineFrame.h" -#include "nsBlockFrame.h" -#include "nsSize.h" -#include "nsIContent.h" -#include "nsIContentDelegate.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsIPresContext.h" -#include "nsIPresShell.h" -#include "nsCSSLayout.h" -#include "nsPlaceholderFrame.h" -#include "nsIReflowCommand.h" -#include "nsHTMLAtoms.h" -#include "nsAbsoluteFrame.h" -#include "nsLeafFrame.h" -#include "nsIPtr.h" - -// XXX To Do: -// 2. horizontal child margins -// 3. borders/padding and splitting -// 4. child relative positioning -// 5. absolutely positioned children -// 6. direction support -// 7. CSS line-height property - -/* XXX */ -#include "nsHTMLIIDs.h" -#include "nsBlockFrame.h" - -#define DEFAULT_ASCENT_LEN 10 - -NS_DEF_PTR(nsIStyleContext); -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIContentDelegate); - -class nsInlineState -{ -public: - const nsStyleFont* font; // style font - nsMargin borderPadding; // inner margin - nsSize mStyleSize; - PRIntn mStyleSizeFlags; - nsSize availSize; // available space in which to reflow (starts as max size minus insets) - nsSize* maxElementSize; // maximum element size (may be null) - nscoord x; // running x-offset (starts at left inner edge) - const nscoord y; // y-offset (top inner edge) - nscoord maxAscent; // max child ascent - nscoord maxDescent; // max child descent - nscoord* ascents; // ascent information for each child - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; - nsLineLayout* lineLayout; - PRBool atBreakPoint; - const nsReflowState& reflowState; - PRBool mNoWrap; - - // Constructor - nsInlineState(nsIPresContext* aPresContext, - nsIFrame* aInlineFrame, - const nsStyleFont* aStyleFont, - const nsMargin& aBorderPadding, - const nsReflowState& aReflowState, - nsSize* aMaxElementSize) - : x(aBorderPadding.left), // determined by inner edge - y(aBorderPadding.top), // determined by inner edge - reflowState(aReflowState) - { - nsBlockReflowState* brs = - nsBlockFrame::FindBlockReflowState(aPresContext, aInlineFrame); - lineLayout = brs->mCurrentLine; - atBreakPoint = PR_TRUE; - - font = aStyleFont; - borderPadding = aBorderPadding; - - unconstrainedWidth = PRBool(reflowState.maxSize.width == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(reflowState.maxSize.height == NS_UNCONSTRAINEDSIZE); - - // If we're constrained adjust the available size so it excludes space - // needed for border/padding - availSize.width = reflowState.maxSize.width; - if (PR_FALSE == unconstrainedWidth) { - availSize.width -= aBorderPadding.left + aBorderPadding.right; - } - availSize.height = reflowState.maxSize.height; - if (PR_FALSE == unconstrainedHeight) { - availSize.height -= aBorderPadding.top + aBorderPadding.bottom; - } - - // Initialize max element size - maxElementSize = aMaxElementSize; - if (nsnull != maxElementSize) { - maxElementSize->SizeTo(0, 0); - } - - ascents = ascentBuf; - maxAscent = 0; - maxDescent = 0; - mNoWrap = PR_FALSE; - } - - void SetNumAscents(PRIntn aNumAscents) { - // We keep around ascent information so that we can vertically align - // children after we figure out how many children fit. - if (aNumAscents > DEFAULT_ASCENT_LEN) { - ascents = new nscoord[aNumAscents]; - } - } - - // Destructor - ~nsInlineState() { - if (ascents != ascentBuf) { - delete ascents; - } - } - -private: - nscoord ascentBuf[DEFAULT_ASCENT_LEN]; -}; - -///////////////////////////////////////////////////////////////////////////// -// - -nsresult nsInlineFrame::NewFrame(nsIFrame** aInstancePtrResult, - nsIContent* aContent, - nsIFrame* aParent) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); - if (nsnull == aInstancePtrResult) { - return NS_ERROR_NULL_POINTER; - } - nsIFrame* it = new nsInlineFrame(aContent, aParent); - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aInstancePtrResult = it; - return NS_OK; -} - -nsInlineFrame::nsInlineFrame(nsIContent* aContent, nsIFrame* aParent) - : nsHTMLContainerFrame(aContent, aParent) -{ - NS_PRECONDITION(!IsPseudoFrame(), "can not be a pseudo frame"); -} - -nsInlineFrame::~nsInlineFrame() -{ -} - -nsReflowStatus -nsInlineFrame::ReflowChild(nsInlineState& aState, - nsIFrame* aKidFrame, - nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState) -{ - nsReflowStatus status; - - NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state"); -#ifdef NS_DEBUG - nsFrameState kidFrameState; - - aKidFrame->GetFrameState(kidFrameState); - NS_ASSERTION(kidFrameState & NS_FRAME_IN_REFLOW, "kid frame is not in reflow"); -#endif - nsIInlineFrame* iif; - if (NS_OK == aKidFrame->QueryInterface(kIInlineFrameIID, (void**)&iif)) { - iif->ReflowInline(*aState.lineLayout, aDesiredSize, aReflowState, status); - } - else { - aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, status); - } - - if (NS_FRAME_IS_COMPLETE(status)) { - nsIFrame* kidNextInFlow; - - aKidFrame->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) - nsIFrame* parent; - - aKidFrame->GetGeometricParent(parent); - DeleteNextInFlowsFor((nsContainerFrame*)parent, aKidFrame); - } - } - return status; -} - -void nsInlineFrame::PlaceChild(nsIFrame* aChild, - PRInt32 aIndex, - nsInlineState& aState, - const nsReflowMetrics& aChildSize, - const nsSize* aChildMaxElementSize) -{ - // Set the child's rect - aChild->SetRect(nsRect(aState.x, aState.y, aChildSize.width, aChildSize.height)); - - // Adjust the running x-offset - aState.x += aChildSize.width; - - // Update the array of ascents and the max ascent and descent - aState.ascents[aIndex] = aChildSize.ascent; - if (aChildSize.ascent > aState.maxAscent) { - aState.maxAscent = aChildSize.ascent; - } - if (aChildSize.descent > aState.maxDescent) { - aState.maxDescent = aChildSize.descent; - } - - // If we're constrained then update the available width - if (!aState.unconstrainedWidth) { - aState.availSize.width -= aChildSize.width; - } - - // Update the maximum element size - if (nsnull != aChildMaxElementSize) { - if (aChildMaxElementSize->width > aState.maxElementSize->width) { - aState.maxElementSize->width = aChildMaxElementSize->width; - } - if (aChildMaxElementSize->height > aState.maxElementSize->height) { - aState.maxElementSize->height = aChildMaxElementSize->height; - } - } -} - -// XXX an image shouldn't be allowed to continue a word but text -// should. hmmm. - -PRBool -nsInlineFrame::CanFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame) -{ - PRBool result = PR_TRUE; - aState.atBreakPoint = nsnull == aState.lineLayout->mBreakFrame; - if ((aState.availSize.width <= 0) && - (aChildFrame != mFirstChild) && (nsnull != mFirstChild)) { - // If we are at a breakable position then it's ok to be out of - // room. Otherwise the child is allowed to fit. - if (aState.atBreakPoint) { - result = PR_FALSE; - } - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsInlineFrame::CanFitChild: availSize=%d result=%s", - aState.availSize.width, result ? "true" : "false")); - return result; -} - -// XXX dup first-child check because of calling code not being nice! ick! -PRBool -nsInlineFrame::DidFitChild(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - nsReflowMetrics& aChildMetrics) -{ - if ((aChildMetrics.width > aState.availSize.width) && - (aChildFrame != mFirstChild) && (nsnull != mFirstChild)) { - // If we *were* at a breakable position then it's ok to be out of - // room. Otherwise the child is allowed to fit. - if (aState.atBreakPoint) { - return PR_FALSE; - } - } - return PR_TRUE; -} - -/** - * Reflow the frames we've already created - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @param aChildFrame the first child frame to reflow - * @param aChildIndex the first child frame's index in the frame list - * @return true if we successfully reflowed all the mapped children and false - * otherwise, e.g. we pushed children to the next in flow - */ -PRBool -nsInlineFrame::ReflowMappedChildrenFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - NS_PRECONDITION(nsnull != aChildFrame, "no children"); - - PRInt32 childCount = aChildIndex; - nsIFrame* prevKidFrame = nsnull; - - // Remember our original mLastContentIsComplete so that if we end up - // having to push children, we have the correct value to hand to - // PushChildren. - PRBool originalLastContentIsComplete = mLastContentIsComplete; - - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; - PRBool result = PR_TRUE; - - for (nsIFrame* kidFrame = aChildFrame; nsnull != kidFrame; ) { - // If the previous child just reflowed has indicated a pending - // break, stop reflowing our remaining children. This can only - // happen when a prev-in-flow has pushed some junk into this - // frame. - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - - result = PR_FALSE; - break; - } - - // If the frame being reflowed is not appropriate (e.g. a block - // frame) then we should stop! This can only happen when a - // prev-in-flow has pushed some junk into this frame. - const nsStyleDisplay* kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if ((NS_STYLE_DISPLAY_BLOCK == kidDisplay->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == kidDisplay->mDisplay)) { - if (mFirstChild != kidFrame) { - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - result = PR_FALSE; - break; - } - } - - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - nsReflowStatus status; - - // Reflow the child into the available space - PRBool room = CanFitChild(aPresContext, aState, kidFrame); - if (room) { - kidFrame->WillReflow(*aPresContext); - status = ReflowChild(aState, kidFrame, aPresContext, kidSize, kidReflowState); - } - - // Did the child fit? - if (!room || !DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child - - // Since we are giving the next-in-flow our last child, we - // give it our original mLastContentIsComplete too (in case we - // are pushing into an empty next-in-flow) - PushChildren(kidFrame, prevKidFrame, originalLastContentIsComplete); - SetLastContentOffset(prevKidFrame); - - result = PR_FALSE; - break; - } - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, childCount, aState, kidSize, pKidMaxElementSize); - childCount++; - - // Remember where we just were in case we end up pushing children - prevKidFrame = kidFrame; - - // Is the child complete? - mLastContentIsComplete = NS_FRAME_IS_COMPLETE(status); - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // No, the child isn't complete - nsIFrame* kidNextInFlow; - - kidFrame->GetNextInFlow(kidNextInFlow); - PRBool lastContentIsComplete = mLastContentIsComplete; - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a continuing - // frame. This hooks the child into the flow - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, - continuingFrame); - NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); - - // Add the continuing frame to the sibling list - nsIFrame* nextSib; - - kidFrame->GetNextSibling(nextSib); - continuingFrame->SetNextSibling(nextSib); - kidFrame->SetNextSibling(continuingFrame); - if (nsnull == nextSib) { - // Assume that the continuation frame we just created is - // complete, for now. It will get reflowed by our - // next-in-flow (we are going to push it now) - lastContentIsComplete = PR_TRUE; - } - } - - // We've used up all of our available space so push the remaining - // children to the next-in-flow - nsIFrame* nextSibling; - - kidFrame->GetNextSibling(nextSibling); - if (nsnull != nextSibling) { - PushChildren(nextSibling, kidFrame, lastContentIsComplete); - SetLastContentOffset(prevKidFrame); - } - result = PR_FALSE; - break; - } - - // Get the next child frame - kidFrame->GetNextSibling(kidFrame); - } - - // Update the child count member data - mChildCount = childCount; -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - NS_POSTCONDITION(LengthOf(mFirstChild) == mChildCount, "bad child count"); - - nsIFrame* lastChild; - PRInt32 lastIndexInParent; - - LastChild(lastChild); - lastChild->GetContentIndex(lastIndexInParent); - NS_POSTCONDITION(lastIndexInParent == mLastContentOffset, "bad last content offset"); - VerifyLastIsComplete(); - } -#endif - return result; -} - -/** - * Try and pull-up frames from our next-in-flow - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @return true if we successfully pulled-up all the children and false - * otherwise, e.g. child didn't fit - */ -PRBool nsInlineFrame::PullUpChildren(nsIPresContext* aPresContext, - nsInlineState& aState) -{ - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("enter nsInlineFrame::PullUpChildren: [%d,%d,%c] childCount=%d", - mFirstContentOffset, - mLastContentOffset, - mLastContentIsComplete ? 'T' : 'F', - mChildCount)); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - - nsInlineFrame* nextInFlow = (nsInlineFrame*)mNextInFlow; - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; -#ifdef NS_DEBUG - PRInt32 kidIndex = NextChildOffset(); -#endif - nsIFrame* prevKidFrame; - - LastChild(prevKidFrame); - - PRBool result = PR_TRUE; - - while (nsnull != nextInFlow) { - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowStatus status; - - // Get the next child - nsIFrame* kidFrame = nextInFlow->mFirstChild; - - // Any more child frames? - if (nsnull == kidFrame) { - // No. Any frames on its overflow list? - if (nsnull != nextInFlow->mOverflowList) { - // Move the overflow list to become the child list - NS_ABORT(); - nextInFlow->AppendChildren(nextInFlow->mOverflowList); - nextInFlow->mOverflowList = nsnull; - kidFrame = nextInFlow->mFirstChild; - } else { - // We've pulled up all the children, so move to the next-in-flow. - nextInFlow = (nsInlineFrame*)nextInFlow->mNextInFlow; - continue; - } - } - - // It's time to stop pulling up if our last child wants a break - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - result = PR_FALSE; - break; - } - - // If the frame being pulled up is not appropriate (e.g. a block - // frame) then we should stop! - const nsStyleDisplay* kidDisplay; - kidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if ((NS_STYLE_DISPLAY_BLOCK == kidDisplay->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == kidDisplay->mDisplay)) { - result = PR_FALSE; - break; - } - - // If there is no room, stop pulling up - if (!CanFitChild(aPresContext, aState, kidFrame)) { - result = PR_FALSE; - break; - } - -// XXX inline reflow avoidance will be done by nsLineLayout -#if XXX - // See if the child fits in the available space. If it fits or - // it's splittable then reflow it. The reason we can't just move - // it is that we still need ascent/descent information - nsSize kidFrameSize; - nsSplittableType kidIsSplittable; - - kidFrame->GetSize(kidFrameSize); - kidFrame->IsSplittable(kidIsSplittable); - if ((kidFrameSize.width > aState.availSize.width) && - NS_FRAME_IS_NOT_SPLITTABLE(kidIsSplittable)) { - result = PR_FALSE; - break; - } -#endif - - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - kidFrame->WillReflow(*aPresContext); - status = ReflowChild(aState, kidFrame, aPresContext, kidSize, kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child - result = PR_FALSE; - break; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsInlineFrame::PullUpChildren: pulled frame=%p [%c][%x]", - kidFrame, - NS_FRAME_IS_COMPLETE(status) ? 'T' : 'F', - status)); - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); - - // Remove the frame from its current parent - kidFrame->GetNextSibling(nextInFlow->mFirstChild); - nextInFlow->mChildCount--; - // Update the next-in-flows first content offset - if (nsnull != nextInFlow->mFirstChild) { - nextInFlow->SetFirstContentOffset(nextInFlow->mFirstChild); - } - - // Link the frame into our list of children - kidFrame->SetGeometricParent(this); - nsIFrame* kidContentParent; - - kidFrame->GetContentParent(kidContentParent); - if (nextInFlow == kidContentParent) { - kidFrame->SetContentParent(this); - } - if (nsnull == prevKidFrame) { - mFirstChild = kidFrame; - SetFirstContentOffset(kidFrame); - } else { - prevKidFrame->SetNextSibling(kidFrame); - } - kidFrame->SetNextSibling(nsnull); - mChildCount++; - prevKidFrame = kidFrame; - - // Is the child we just pulled up complete? - mLastContentIsComplete = NS_FRAME_IS_COMPLETE(status); - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // No the child isn't complete - nsIFrame* kidNextInFlow; - - kidFrame->GetNextInFlow(kidNextInFlow); - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a - // continuing frame. The creation appends it to the flow and - // prepares it for reflow. - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, - continuingFrame); - NS_ASSERTION(nsnull != continuingFrame, "frame creation failed"); - - // Add the continuing frame to our sibling list and then push - // it to the next-in-flow. This ensures the next-in-flow's - // content offsets and child count are set properly. Note that - // we can safely assume that the continuation is complete so - // we pass PR_TRUE into PushChidren in case our next-in-flow - // was just drained and now needs to know it's - // mLastContentIsComplete state. - kidFrame->SetNextSibling(continuingFrame); - - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsInlineFrame::PullUpChildren: pushing frame=%p", - continuingFrame)); - PushChildren(continuingFrame, kidFrame, PR_TRUE); - - // After we push the continuation frame we don't need to fuss - // with mLastContentIsComplete beause the continuation frame - // is no longer on *our* list. - } - - // If the child isn't complete then it means that we've used up - // all of our available space. - result = PR_FALSE; - break; - } - } - - // Update our last content offset - if (nsnull != prevKidFrame) { - NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child"); - SetLastContentOffset(prevKidFrame); - } - - // We need to make sure the first content offset is correct for any empty - // next-in-flow frames (frames where we pulled up all the child frames) - nextInFlow = (nsInlineFrame*)mNextInFlow; - if ((nsnull != nextInFlow) && (nsnull == nextInFlow->mFirstChild)) { - // We have at least one empty frame. Did we succesfully pull up all the - // child frames? - if (PR_FALSE == result) { - // No, so we need to adjust the first content offset of all the empty - // frames - AdjustOffsetOfEmptyNextInFlows(); -#ifdef NS_DEBUG - } else { - // Yes, we successfully pulled up all the child frames which means all - // the next-in-flows must be empty. Do a sanity check - if (GetVerifyTreeEnable()) { - while (nsnull != nextInFlow) { - NS_ASSERTION(nsnull == nextInFlow->mFirstChild, - "non-empty next-in-flow"); - nextInFlow = (nsInlineFrame*)nextInFlow->mNextInFlow; - } - } -#endif - } - } - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("exit nsInlineFrame::PullUpChildren: [%d,%d,%c] childCount=%d", - mFirstContentOffset, - mLastContentOffset, - mLastContentIsComplete ? 'T' : 'F', - mChildCount)); - return result; -} - -/** - * Create new frames for content we haven't yet mapped - * - * @param aPresContext presentation context to use - * @param aState current inline state - * @return NS_FRAME_COMPLETE if all content has been mapped and 0 if we - * should be continued - */ -nsReflowStatus -nsInlineFrame::ReflowUnmappedChildren(nsIPresContext* aPresContext, - nsInlineState& aState) -{ -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - VerifyLastIsComplete(); - } -#endif - nsIFrame* kidPrevInFlow = nsnull; - nsReflowStatus result = NS_FRAME_NOT_COMPLETE; - - // If we have no children and we have a prev-in-flow then we need to pick - // up where it left off. If we have children, e.g. we're being resized, then - // our content offset should already be set correctly... - if ((nsnull == mFirstChild) && (nsnull != mPrevInFlow)) { - nsInlineFrame* prev = (nsInlineFrame*)mPrevInFlow; - NS_ASSERTION(prev->mLastContentOffset >= prev->mFirstContentOffset, - "bad prevInFlow"); - - mFirstContentOffset = prev->NextChildOffset(); - if (!prev->mLastContentIsComplete) { - // Our prev-in-flow's last child is not complete - prev->LastChild(kidPrevInFlow); - } - } - mLastContentIsComplete = PR_TRUE; - - // Place our children, one at a time until we are out of children - nsSize kidMaxElementSize; - nsSize* pKidMaxElementSize = - (nsnull != aState.maxElementSize) ? &kidMaxElementSize : nsnull; - PRInt32 kidIndex = NextChildOffset(); - nsIFrame* prevKidFrame; - - PRBool breakAfter = PR_FALSE; - LastChild(prevKidFrame); - for (;;) { - // Get the next content object - nsIContentPtr kid = mContent->ChildAt(kidIndex); - if (kid.IsNull()) { - result = NS_FRAME_COMPLETE; - break; - } - - // It's time to stop pulling up if our previous child wants a line - // break - if (NS_STYLE_CLEAR_NONE != aState.lineLayout->mPendingBreak) { - break; - } - - // Make sure we still have room left - if (!CanFitChild(aPresContext, aState, nsnull)) { - // Note: return status was set to 0 above... - break; - } - - // Resolve style for the child - nsIStyleContextPtr kidStyleContext = - aPresContext->ResolveStyleContextFor(kid, this); - - // Figure out how we should treat the child - nsIFrame* kidFrame; - const nsStyleDisplay* kidDisplay = - (const nsStyleDisplay*)kidStyleContext->GetStyleData(eStyleStruct_Display); - const nsStylePosition* kidPosition = (const nsStylePosition*) - kidStyleContext->GetStyleData(eStyleStruct_Position); - - // Check whether it wants to floated or absolutely positioned - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == kidPosition->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - } else if (kidDisplay->mFloats != NS_STYLE_FLOAT_NONE) { - rv = nsPlaceholderFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - } else if (nsnull == kidPrevInFlow) { - nsIContentDelegatePtr kidDel; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - if (kidIndex != mFirstContentOffset) { - // We don't allow block elements to be placed in us anywhere - // other than at our left margin. - goto done; - } - // FALLTHROUGH - - case NS_STYLE_DISPLAY_INLINE: - kidDel = kid->GetDelegate(aPresContext); - rv = kidDel->CreateFrame(aPresContext, kid, this, - kidStyleContext, kidFrame); - break; - - default: - NS_ASSERTION(nsnull == kidPrevInFlow, "bad prev in flow"); - rv = nsFrame::NewFrame(&kidFrame, kid, this); - if (NS_OK == rv) { - kidFrame->SetStyleContext(aPresContext, kidStyleContext); - } - break; - } - } else { - rv = kidPrevInFlow->CreateContinuingFrame(aPresContext, this, - kidStyleContext, kidFrame); - } - - // Try to reflow the child into the available space. It might not - // fit or might need continuing. - nsReflowMetrics kidSize(pKidMaxElementSize); - nsReflowState kidReflowState(kidFrame, aState.reflowState, aState.availSize, - eReflowReason_Resize); - kidFrame->WillReflow(*aPresContext); - nsReflowStatus status = ReflowChild(aState, kidFrame, aPresContext, kidSize, - kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, aState, kidFrame, kidSize)) { - // The child is too wide to fit in the available space, and it's - // not our first child. Add the frame to our overflow list - NS_ASSERTION(nsnull == mOverflowList, "bad overflow list"); - mOverflowList = kidFrame; - prevKidFrame->SetNextSibling(nsnull); - break; - } - - // Place and size the child. We'll deal with vertical alignment when - // we're all done - PlaceChild(kidFrame, mChildCount, aState, kidSize, pKidMaxElementSize); - - // Link child frame into the list of children - if (nsnull != prevKidFrame) { - prevKidFrame->SetNextSibling(kidFrame); - } else { - mFirstChild = kidFrame; // our first child - SetFirstContentOffset(kidFrame); - } - prevKidFrame = kidFrame; - mChildCount++; - kidIndex++; - - // Did the child complete? - if (NS_FRAME_IS_NOT_COMPLETE(status)) { - // If the child isn't complete then it means that we've used up - // all of our available space - mLastContentIsComplete = PR_FALSE; - break; - } - kidPrevInFlow = nsnull; - - // If we need to break after the kidFrame, then do so now - if (breakAfter) { - break; - } - } - -done:; - // Update the content mapping - NS_ASSERTION(IsLastChild(prevKidFrame), "bad last child"); - SetLastContentOffset(prevKidFrame); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PRInt32 len = LengthOf(mFirstChild); - NS_ASSERTION(len == mChildCount, "bad child count"); - VerifyLastIsComplete(); - } -#endif - return result; -} - -void -nsInlineFrame::InitializeState(nsIPresContext* aPresContext, - const nsReflowState& aReflowState, - nsInlineState& aState) -{ - PRIntn ss = aState.mStyleSizeFlags = - nsCSSLayout::GetStyleSize(aPresContext, aReflowState, aState.mStyleSize); - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - // When we are given a width, change the reflow behavior to - // unconstrained. - aState.unconstrainedWidth = PR_TRUE; - aState.availSize.width = NS_UNCONSTRAINEDSIZE; - } -} - -NS_METHOD nsInlineFrame::Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("enter nsInlineFrame::Reflow: this=%p: childCount=%d", - this, mChildCount)); -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PreReflowCheck(); - } -#endif - - if (eReflowReason_Initial == aReflowState.reason) { - nsresult rv = ProcessInitialReflow(aPresContext); - if (NS_OK != rv) { - return rv; - } - } - - PRBool reflowMappedOK = PR_TRUE; - - aStatus = NS_FRAME_COMPLETE; // initialize out parameter - - // Get the style molecule - const nsStyleFont* styleFont = (const nsStyleFont*) - mStyleContext->GetStyleData(eStyleStruct_Font); - const nsStyleSpacing* styleSpacing = (const nsStyleSpacing*) - mStyleContext->GetStyleData(eStyleStruct_Spacing); - const nsStyleText* styleText = (const nsStyleText*) - mStyleContext->GetStyleData(eStyleStruct_Text); - - // Check for an overflow list - if (eReflowReason_Incremental != aReflowState.reason) { - MoveOverflowToChildList(); - } - - // Initialize our reflow state. We must wait until after we've processed - // the overflow list, because our first content offset might change - nsMargin borderPadding; - styleSpacing->CalcBorderPaddingFor(this, borderPadding); - nsInlineState state(aPresContext, this, styleFont, borderPadding, - aReflowState, aDesiredSize.maxElementSize); - InitializeState(aPresContext, aReflowState, state); - state.SetNumAscents(mContent->ChildCount() - mFirstContentOffset); - state.mNoWrap = NS_STYLE_WHITESPACE_NORMAL != styleText->mWhiteSpace; - - if (eReflowReason_Incremental == aReflowState.reason) { - NS_ASSERTION(nsnull != aReflowState.reflowCommand, "null reflow command"); - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - - if (target == this) { - nsIReflowCommand::ReflowType type; - aReflowState.reflowCommand->GetType(type); - - switch (type) { - case nsIReflowCommand::FrameAppended: - // Recover our state - RecoverState(aPresContext, state, nsnull); - aStatus = ReflowUnmappedChildren(aPresContext, state); - break; - - default: - NS_NOTYETIMPLEMENTED("unexpected reflow command"); - break; - } - - } else { - // The command is passing through us. Get the next frame in the reflow chain - nsIFrame* kidFrame; - aReflowState.reflowCommand->GetNext(kidFrame); - - nsReflowMetrics kidSize(aDesiredSize.maxElementSize); - nsReflowState kidReflowState(kidFrame, aReflowState, state.availSize); - - // Restore our state as if nextFrame is the next frame to reflow - PRInt32 kidIndex = RecoverState(aPresContext, state, kidFrame); - - // Reflow the child into the available space - kidFrame->WillReflow(*aPresContext); - aStatus = ReflowChild(state, kidFrame, aPresContext, kidSize, kidReflowState); - - // Did the child fit? - if (!DidFitChild(aPresContext, state, kidFrame, kidSize)) { - nsIFrame* prevFrame; - - // The child is too wide to fit in the available space, and - // it's not our first child - PrevChild(kidFrame, prevFrame); - PushChildren(kidFrame, prevFrame, mLastContentIsComplete); - SetLastContentOffset(prevFrame); - mChildCount = kidIndex - 1; - aStatus = NS_FRAME_NOT_COMPLETE; - - } else { - // Place and size the child - PlaceChild(kidFrame, kidIndex, state, kidSize, nsnull); - - nsIFrame* kidNextInFlow; - kidFrame->GetNextInFlow(kidNextInFlow); - - // Is the child complete? - if (NS_FRAME_IS_COMPLETE(aStatus)) { - // Check whether the frame has next-in-flow(s) that are no longer needed - if (nsnull != kidNextInFlow) { - // Remove the next-in-flow(s) - DeleteChildsNextInFlow(kidFrame); - } - - // Adjust the frames that follow - aStatus = IncrementalReflowAfter(aPresContext, state, kidFrame, kidIndex); - - } else { - nsIFrame* nextSibling; - - // No, the child isn't complete - if (nsnull == kidNextInFlow) { - // The child doesn't have a next-in-flow so create a continuing - // frame. - nsIFrame* continuingFrame; - - nsIStyleContextPtr kidSC; - kidFrame->GetStyleContext(aPresContext, kidSC.AssignRef()); - kidFrame->CreateContinuingFrame(aPresContext, this, kidSC, continuingFrame); - - // Link the child into the sibling list - kidFrame->GetNextSibling(nextSibling); - continuingFrame->SetNextSibling(nextSibling); - kidFrame->SetNextSibling(continuingFrame); - } - - // We've used up all of our available space, so push the remaining - // children to the next-in-flow - kidFrame->GetNextSibling(nextSibling); - if (nsnull != nextSibling) { - PushChildren(nextSibling, kidFrame, mLastContentIsComplete); - } - - SetLastContentOffset(kidFrame); - mChildCount = kidIndex; - } - } - } - - } else { - // Reflow any existing frames - if (nsnull != mFirstChild) { - reflowMappedOK = ReflowMappedChildrenFrom(aPresContext, state, mFirstChild, 0); - - if (PR_FALSE == reflowMappedOK) { - // We didn't successfully reflow our mapped frames; therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } - - // Did we successfully relow our mapped children? - if (PR_TRUE == reflowMappedOK) { -#if XXX - // Any space left? - if (state.availSize.width <= 0) { - // No space left. Don't try to pull-up children or reflow unmapped - if (NextChildOffset() < mContent->ChildCount()) { - // No room left to map the remaining content; therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } else -#endif - if (NextChildOffset() < mContent->ChildCount()) { - // Try and pull-up some children from a next-in-flow - if (PullUpChildren(aPresContext, state)) { - // If we still have unmapped children then create some new frames - if (NextChildOffset() < mContent->ChildCount()) { - aStatus = ReflowUnmappedChildren(aPresContext, state); - } - } else { - // We were unable to pull-up all the existing frames from the next in flow; - // therefore, we're not complete - aStatus = NS_FRAME_NOT_COMPLETE; - } - } - } - - #if 0 - // XXX I don't think our return size properly accounts for the lineHeight - // (which may not == state.maxAscent + state.maxDescent) - // Return our size and our status - #endif - } - - // Vertically align the children - nscoord lineHeight = - nsCSSLayout::VerticallyAlignChildren(aPresContext, this, styleFont, - borderPadding.top, - mFirstChild, mChildCount, - state.ascents, state.maxAscent); - - ComputeFinalSize(aPresContext, state, aDesiredSize); - -#ifdef NS_DEBUG - if (GetVerifyTreeEnable()) { - PostReflowCheck(aStatus); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("exit nsInlineFrame::Reflow: this=%p: childCount=%d status=%scomplete", - this, mChildCount, - NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ")); - return NS_OK; -} - -void -nsInlineFrame::ComputeFinalSize(nsIPresContext* aPresContext, - nsInlineState& aState, - nsReflowMetrics& aDesiredSize) -{ - // Compute default size - aDesiredSize.width = aState.x + aState.borderPadding.right; - aDesiredSize.ascent = aState.borderPadding.top + aState.maxAscent; - aDesiredSize.descent = aState.maxDescent + aState.borderPadding.bottom; - aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; - - // Apply width/height style properties - PRIntn ss = aState.mStyleSizeFlags; - if (0 != (ss & NS_SIZE_HAS_WIDTH)) { - aDesiredSize.width = aState.borderPadding.left + aState.mStyleSize.width + - aState.borderPadding.right; - } - if (0 != (ss & NS_SIZE_HAS_HEIGHT)) { - aDesiredSize.height = aState.borderPadding.top + aState.mStyleSize.height + - aState.borderPadding.bottom; - } - - if ((nsnull != aDesiredSize.maxElementSize) && aState.mNoWrap) { - aDesiredSize.maxElementSize->width = aDesiredSize.width; - aDesiredSize.maxElementSize->height = aDesiredSize.height; - } -} - -///////////////////////////////////////////////////////////////////////////// - -PRIntn nsInlineFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - skip |= 1 << NS_SIDE_LEFT; - } - if (nsnull != mNextInFlow) { - skip |= 1 << NS_SIDE_RIGHT; - } - return skip; -} - -///////////////////////////////////////////////////////////////////////////// - -// Incremental reflow support - -NS_METHOD nsInlineFrame::GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics) -{ - nscoord maxAscent = 0; - nscoord maxDescent = 0; - nsIFrame* kid = mFirstChild; - while (nsnull != kid) { - // XXX Properly handle max element size... - nsReflowMetrics kidMetrics(aMetrics.maxElementSize); - kid->GetReflowMetrics(aPresContext, kidMetrics); - if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; - if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; - kid->GetNextSibling(kid); - } - - // XXX what about border & padding - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - aMetrics.ascent = maxAscent; - aMetrics.descent = maxDescent; - - return NS_OK; -} - -/** - * Setup aState to the state it would have had we just reflowed our - * children up to, but not including, aSkipChild. Return the index - * of aSkipChild in our list of children. - * If aSkipChild is nsnull then resets the state for appended content. - */ -PRInt32 nsInlineFrame::RecoverState(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aSkipChild) -{ - // Get ascent & descent info for all the children up to but not - // including aSkipChild. Also compute the x coordinate for where - // aSkipChild will be place after it is reflowed. - PRInt32 i = 0; - nsIFrame* kid = mFirstChild; - nscoord x = aState.x; - nscoord maxAscent = 0; - nscoord maxDescent = 0; - while ((nsnull != kid) && (kid != aSkipChild)) { - nsReflowMetrics kidMetrics(nsnull); - kid->GetReflowMetrics(aPresContext, kidMetrics); - aState.ascents[i] = kidMetrics.ascent; - if (kidMetrics.ascent > maxAscent) maxAscent = kidMetrics.ascent; - if (kidMetrics.descent > maxDescent) maxDescent = kidMetrics.descent; - - // XXX Factor in left and right margins - x += kidMetrics.width; - - kid->GetNextSibling(kid); - i++; - } - aState.maxAscent = maxAscent; - aState.maxDescent = maxDescent; - aState.x = x; - return i; -} - -// XXX We need to return information about whether our next-in-flow is -// dirty... -nsReflowStatus -nsInlineFrame::IncrementalReflowFrom(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ - nsReflowStatus status = NS_FRAME_COMPLETE; - - // Just reflow all the mapped children starting with childFrame. - // XXX This isn't the optimal thing to do... - if (ReflowMappedChildrenFrom(aPresContext, aState, aChildFrame, aChildIndex)) { - if (NextChildOffset() < mContent->ChildCount()) { -#if XXX - // Any space left? - if (aState.availSize.width <= 0) { - // No space left. Don't try to pull-up children - status = NS_FRAME_NOT_COMPLETE; - } else -#endif - { - // Try and pull-up some children from a next-in-flow - if (!PullUpChildren(aPresContext, aState)) { - // We were not able to pull-up all the child frames from our - // next-in-flow - status = NS_FRAME_NOT_COMPLETE; - } - } - } - } else { - // We were unable to reflow all our mapped frames - status = NS_FRAME_NOT_COMPLETE; - } - - return status; -} - -nsReflowStatus -nsInlineFrame::IncrementalReflowAfter(nsIPresContext* aPresContext, - nsInlineState& aState, - nsIFrame* aChildFrame, - PRInt32 aChildIndex) -{ - nsReflowStatus status = NS_FRAME_COMPLETE; - nsIFrame* nextFrame; - - aChildFrame->GetNextSibling(nextFrame); - - // Just reflow all the remaining mapped children - // XXX This isn't the optimal thing to do... - if ((nsnull == nextFrame) || - ReflowMappedChildrenFrom(aPresContext, aState, nextFrame, aChildIndex + 1)) { - if (NextChildOffset() < mContent->ChildCount()) { -#if XXX - // Any space left? - if (aState.availSize.width <= 0) { - // No space left. Don't try to pull-up children - status = NS_FRAME_NOT_COMPLETE; - } else -#endif - { - // Try and pull-up some children from a next-in-flow - if (!PullUpChildren(aPresContext, aState)) { - // We were not able to pull-up all the child frames from our - // next-in-flow - status = NS_FRAME_NOT_COMPLETE; - } - } - } - } else { - // We were unable to reflow all our mapped frames - status = NS_FRAME_NOT_COMPLETE; - } - - return status; -} - -// In order to execute the vertical alignment code after incremental -// reflow of the inline frame, we need to reposition any child frames -// that were relatively positioned back to their computed x origin. -// This should probably be done as a pre-alignment computation (and it -// can be avoided if there are no relatively positioned children). diff --git a/mozilla/layout/html/base/src/nsLeafFrame.cpp b/mozilla/layout/html/base/src/nsLeafFrame.cpp index cb98d4125ea..601c890906d 100644 --- a/mozilla/layout/html/base/src/nsLeafFrame.cpp +++ b/mozilla/layout/html/base/src/nsLeafFrame.cpp @@ -60,6 +60,7 @@ NS_METHOD nsLeafFrame::Reflow(nsIPresContext* aPresContext, // XXX add in code to check for width/height being set via css // and if set use them instead of calling GetDesiredSize. + GetDesiredSize(aPresContext, aReflowState, aDesiredSize); AddBordersAndPadding(aPresContext, aDesiredSize); if (nsnull != aDesiredSize.maxElementSize) { diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp deleted file mode 100644 index 1b651ec97b3..00000000000 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ /dev/null @@ -1,1695 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#include "nsLineLayout.h" -#include "nsIStyleContext.h" -#include "nsStyleConsts.h" -#include "nsBlockFrame.h" -#include "nsIContent.h" -#include "nsIContentDelegate.h" -#include "nsIPresContext.h" -#include "nsISpaceManager.h" -#include "nsIPtr.h" -#include "nsAbsoluteFrame.h" -#include "nsPlaceholderFrame.h" -#include "nsCSSLayout.h" -#include "nsCRT.h" -#include "nsIReflowCommand.h" -#include "nsIFontMetrics.h" -#include "nsHTMLBase.h" -#include "nsScrollFrame.h" - -#undef NOISY_REFLOW - -// XXX zap mAscentNum - -NS_DEF_PTR(nsIContent); -NS_DEF_PTR(nsIStyleContext); - -nsLineData::nsLineData() -{ - mNextLine = nsnull; - mPrevLine = nsnull; - mFirstChild = nsnull; - mChildCount = 0; - mFirstContentOffset = 0; - mLastContentOffset = 0; - mLastContentIsComplete = PR_TRUE; - mIsBlock = PR_FALSE; - mBounds.SetRect(0, 0, 0, 0); - mFloaters = nsnull; -} - -nsLineData::~nsLineData() -{ - delete mFloaters; -} - -void -nsLineData::UnlinkLine() -{ - nsLineData* prevLine = mPrevLine; - nsLineData* nextLine = mNextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; -} - -nsresult -nsLineData::Verify(PRBool aFinalCheck) const -{ - NS_ASSERTION(mNextLine != this, "bad line linkage"); - NS_ASSERTION(mPrevLine != this, "bad line linkage"); - if (nsnull != mPrevLine) { - NS_ASSERTION(mPrevLine->mNextLine == this, "bad line linkage"); - } - if (nsnull != mNextLine) { - NS_ASSERTION(mNextLine->mPrevLine == this, "bad line linkage"); - } - - if (aFinalCheck) { - NS_ASSERTION(0 != mChildCount, "empty line"); - NS_ASSERTION(nsnull != mFirstChild, "empty line"); - - nsIFrame* nextLinesFirstChild = nsnull; - if (nsnull != mNextLine) { - nextLinesFirstChild = mNextLine->mFirstChild; - } - - // Check that number of children are ok and that the index in parent - // information agrees with the content offsets. - PRInt32 offset = mFirstContentOffset; - PRInt32 len = 0; - nsIFrame* child = mFirstChild; - while ((nsnull != child) && (child != nextLinesFirstChild)) { - PRInt32 indexInParent; - child->GetContentIndex(indexInParent); - NS_ASSERTION(indexInParent == offset, "bad line offsets"); - len++; - if (len != mChildCount) { - offset++; - } - child->GetNextSibling(child); - } - NS_ASSERTION(offset == mLastContentOffset, "bad mLastContentOffset"); - NS_ASSERTION(len == mChildCount, "bad child count"); - } - - if (1 == mChildCount) { - if (mIsBlock) { - nsIFrame* child = mFirstChild; - const nsStyleDisplay* display; - child->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display); - NS_ASSERTION((NS_STYLE_DISPLAY_BLOCK == display->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay), - "bad mIsBlock state"); - } - } - - // XXX verify content offsets and mLastContentIsComplete - return NS_OK; -} - -nsIFrame* -nsLineData::GetLastChild() -{ - nsIFrame* lastChild = mFirstChild; - if (mChildCount > 1) { - for (PRInt32 numKids = mChildCount - 1; --numKids >= 0; ) { - nsIFrame* nextChild; - lastChild->GetNextSibling(nextChild); - lastChild = nextChild; - } - } - return lastChild; -} - -PRIntn -nsLineData::GetLineNumber() const -{ - PRIntn lineNumber = 0; - nsLineData* prev = mPrevLine; - while (nsnull != prev) { - lineNumber++; - prev = prev->mPrevLine; - } - return lineNumber; -} - -void -nsLineData::List(FILE* out, PRInt32 aIndent) const -{ - // Indent - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - - // Output the first/last content offset - fprintf(out, "line %d [%d,%d,%c] ", - GetLineNumber(), - mFirstContentOffset, mLastContentOffset, - (mLastContentIsComplete ? 'T' : 'F')); - - // Output the bounds rect - out << mBounds; - - // Output the children, one line at a time - if (nsnull != mFirstChild) { - fputs("<\n", out); - aIndent++; - - nsIFrame* child = mFirstChild; - for (PRInt32 numKids = mChildCount; --numKids >= 0; ) { - child->List(out, aIndent); - child->GetNextSibling(child); - } - - aIndent--; - for (PRInt32 i = aIndent; --i >= 0; ) fputs(" ", out); - fputs(">\n", out); - } else { - fputs("<>\n", out); - } -} - -//---------------------------------------------------------------------- - -nsLineLayout::nsLineLayout(nsBlockReflowState& aState) - : mBlockReflowState(aState) -{ - mBlock = aState.mBlock; - mSpaceManager = aState.mSpaceManager; - mBlock->GetContent(mBlockContent); - mPresContext = aState.mPresContext; - mUnconstrainedWidth = aState.mUnconstrainedWidth; - mUnconstrainedHeight = aState.mUnconstrainedHeight; - mMaxElementSizePointer = aState.mMaxElementSizePointer; - - mAscents = mAscentBuf; - mMaxAscents = sizeof(mAscentBuf) / sizeof(mAscentBuf[0]); -} - -nsLineLayout::~nsLineLayout() -{ - NS_IF_RELEASE(mBlockContent); - if (mAscents != mAscentBuf) { - delete [] mAscents; - } -} - -nsresult -nsLineLayout::Initialize(nsBlockReflowState& aState, nsLineData* aLine) -{ - nsresult rv = NS_OK; - - SetReflowSpace(aState.mCurrentBand.availSpace); - - mState.mSkipLeadingWhiteSpace = PR_TRUE; - mState.mColumn = 0; - - mState.mKidFrame = nsnull; - mState.mPrevKidFrame = nsnull; - mState.mKidIndex = aLine->mFirstContentOffset; - mState.mKidFrameNum = 0; - mState.mMaxElementSize.width = 0; - mState.mMaxElementSize.height = 0; - mState.mMaxAscent = nsnull; - mState.mMaxDescent = nsnull; - - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - mPendingBreak = NS_STYLE_CLEAR_NONE; - - mLine = aLine; - mKidPrevInFlow = nsnull; - mNewFrames = 0; - mFramesReflowed = 0; - - mMarginApplied = PR_FALSE; - - mMustReflowMappedChildren = PR_FALSE; - mY = aState.mY; - mMaxHeight = aState.mAvailSize.height; - mReflowDataChanged = PR_FALSE; - - mLineHeight = 0; - - mNoWrap = PR_FALSE; - const nsStyleText* styleText; - mBlock->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&)styleText); - switch (styleText->mWhiteSpace) { - case NS_STYLE_WHITESPACE_PRE: - case NS_STYLE_WHITESPACE_NOWRAP: - mNoWrap = PR_TRUE; - break; - } - - return rv; -} - -void -nsLineLayout::SetReflowSpace(nsRect& aAvailableSpaceRect) -{ - nscoord x0 = aAvailableSpaceRect.x; - mLeftEdge = x0; - mState.mX = x0; - mRightEdge = x0 + aAvailableSpaceRect.width; - - mMaxWidth = mRightEdge - x0; - mReflowDataChanged = PR_TRUE; - mMustReflowMappedChildren = PR_TRUE; -} - -nsresult -nsLineLayout::SetAscent(nscoord aAscent) -{ - PRInt32 kidFrameNum = mState.mKidFrameNum; - if (kidFrameNum == mMaxAscents) { - mMaxAscents *= 2; - nscoord* newAscents = new nscoord[mMaxAscents]; - if (nsnull != newAscents) { - nsCRT::memcpy(newAscents, mAscents, sizeof(nscoord) * kidFrameNum); - if (mAscents != mAscentBuf) { - delete [] mAscents; - } - mAscents = newAscents; - } else { - return NS_ERROR_OUT_OF_MEMORY; - } - } - mAscents[kidFrameNum] = aAscent; - return NS_OK; -} - -void -nsLineLayout::AtSpace() -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtSpace: kidFrame=%p kidIndex=%d mX=%d", - mState.mKidFrame, mState.mKidIndex, mState.mX)); - mBreakFrame = nsnull; - mSavedState.mKidFrame = nsnull; -} - -void -nsLineLayout::AtWordStart(nsIFrame* aFrame, nscoord aX) -{ - if (nsnull == mBreakFrame) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtWordStart: aFrame=%p kidFrame=%p[%d] aX=%d mX=%d", - aFrame, - mState.mKidFrame, mState.mKidIndex, - aX, mState.mX)); - - mSavedState = mState; - mBreakFrame = aFrame; - mBreakX = aX; - } - else if (mBreakFrame == aFrame) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::AtWordStart: update aX=%d", aX)); - NS_ASSERTION((mSavedState.mKidFrame == mState.mKidFrame) && - (mSavedState.mKidIndex == mState.mKidIndex) && - (mSavedState.mKidFrameNum == mState.mKidFrameNum), - "bad break state"); - mBreakX = aX; - } -} - -PRBool -nsLineLayout::CanBreak() -{ - if (nsnull == mBreakFrame) { - // There is no word to break at - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: no break frame")); - return PR_FALSE; - } - - if (mSavedState.mKidFrame == mLine->mFirstChild) { - // The line's first frame contains the break position; we are not - // allowed to break if the break would empty the line. - if (0 == mBreakX) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: breakX=0")); - return PR_FALSE; - } - } - - // Compute the break x coordinate in our coordinate system by adding - // in the X coordinates of each of the frames between the break - // frame and the containing block frame. - nscoord breakX = mBreakX; - nsIFrame* frame = mBreakFrame; - for (;;) { - nsRect r; - frame->GetRect(r); - breakX += r.x; - nsIFrame* parent; - frame->GetGeometricParent(parent); - if (parent == mBlock) { - break; - } - frame = parent; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::CanBreak: backup from=%p[%d]/%d to=%p[%d]/%d breakX=%d", - mState.mKidFrame, mState.mKidIndex, mState.mKidFrameNum, - mSavedState.mKidFrame, mSavedState.mKidIndex, mSavedState.mKidFrameNum, - breakX)); - - // Revert the line layout back to where it was when the break point - // was found. - mState = mSavedState; - - // Change the right edge to the breakX so that when we reflow the - // child it will stop just before the break point. - mRightEdge = breakX; - - // Forgot word break - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - - return PR_TRUE; -} - -/** - * Attempt to avoid reflowing a child by seeing if it's been touched - * since the last time it was reflowed. - */ -nsresult -nsLineLayout::ReflowMappedChild() -{ - nsIFrame* kidFrame = mState.mKidFrame; - - if (mMustReflowMappedChildren || PR_TRUE) { -/* - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: must reflow frame=%p[%d]", - kidFrame, mKidIndex)); -*/ - return ReflowChild(nsnull, PR_FALSE); - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: attempt frame=%p[%d]", - kidFrame, mState.mKidIndex)); - - // If the child is a container then we need to reflow it if there is - // a change in width. Note that if it's an empty container then it - // doesn't really matter how much space we give it. - if (mBlockReflowState.mDeltaWidth != 0) { - nsIFrame* f; - kidFrame->FirstChild(f); - if (nsnull != f) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: has children")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // If we need the max-element size and we are splittable then we - // have to reflow to get it. - nsSplittableType splits; - kidFrame->IsSplittable(splits); -#if 0 - if (nsnull != mMaxElementSizePointer) { - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: need max-element-size")); - return ReflowChild(nsnull, PR_FALSE); - } - } -#else - // XXX For now, if the child is splittable we reflow it. The reason - // is that the text whitespace compression needs to be consulted - // here to properly handle reflow avoidance. To do that properly we - // really need a first-rate protocol here (WillPlace? - // CanAvoidReflow?) that gets the frame involved. - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: splittable hack")); - return ReflowChild(nsnull, PR_FALSE); - } -#endif - - nsFrameState state; - kidFrame->GetFrameState(state); - - // XXX a better term for this is "dirty" and once we add a dirty - // bit that's what we'll do here. - - // XXX this check will cause pass2 of table reflow to reflow - // everything; tables will be even faster if we have a dirty bit - // instead (that way we can avoid reflowing non-splittables on - // pass2) - if (0 != (state & NS_FRAME_IN_REFLOW)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: frame is dirty")); - return ReflowChild(nsnull, PR_FALSE); - } - - if (NS_FRAME_IS_SPLITTABLE(splits)) { - // XXX a next-in-flow propogated dirty-bit eliminates this code - - // The splittable frame has not yet been reflowed. This means - // that, in theory, its state is well defined. However, if it has - // a prev-in-flow and that frame has been touched then we need to - // reflow this frame. - nsIFrame* prevInFlow; - kidFrame->GetPrevInFlow(prevInFlow); - if (nsnull != prevInFlow) { - nsFrameState prevState; - prevInFlow->GetFrameState(prevState); - if (0 != (prevState & NS_FRAME_IN_REFLOW)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: prev-in-flow frame is dirty")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // If the child has a next-in-flow then never-mind, we need to - // reflow it in case it has more/less space to reflow into. - nsIFrame* nextInFlow; - kidFrame->GetNextInFlow(nextInFlow); - if (nsnull != nextInFlow) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: frame has next-in-flow")); - return ReflowChild(nsnull, PR_FALSE); - } - } - - // Success! We have (so far) avoided reflowing the child. However, - // we do need to place it and advance our position state. Get the - // size of the child and its reflow metrics for placing. - nsIStyleContextPtr kidSC; - nsresult rv = kidFrame->GetStyleContext(mPresContext, kidSC.AssignRef()); - if (NS_OK != rv) { - return rv; - } - const nsStyleDisplay* kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_FLOAT_NONE != kidDisplay->mFloats) { - // XXX If it floats it needs to go through the normal path so that - // PlaceFloater is invoked. - return ReflowChild(nsnull, PR_FALSE); - } - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); - PRBool isBlock = PR_FALSE; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - if (kidFrame != mLine->mFirstChild) { - // Block items must be at the start of a line, therefore we need - // to break before the block item. - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: block requires break-before")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - isBlock = PR_TRUE; - break; - } - - // Compute new total width of child using its current margin values - // (they may have changed since the last time the child was reflowed) - nsRect kidRect; - kidFrame->GetRect(kidRect); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - nscoord totalWidth; - totalWidth = kidMargin.left + kidMargin.right + kidRect.width; - - // If the child intersects the area affected by the reflow then - // we need to reflow it. - nscoord x = mState.mX; - if (x + kidMargin.left + kidRect.width > mRightEdge) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: failed edge test")); - // XXX if !splittable then return NS_LINE_LAYOUT_BREAK_BEFORE - return ReflowChild(nsnull, PR_FALSE); - } - - // Make sure the child will fit. The child always fits if it's the - // first child on the line. - nscoord availWidth = mRightEdge - x; - if (mUnconstrainedWidth || - (kidFrame == mLine->mFirstChild) || - (totalWidth <= availWidth)) { - // By convention, mReflowResult is set during ResizeReflow, - // IncrementalReflow AND GetReflowMetrics by those frames that are - // line layout aware. - mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; - nsReflowMetrics kidMetrics(nsnull); - kidFrame->GetReflowMetrics(mPresContext, kidMetrics); - - nsSize maxElementSize; - nsSize* kidMaxElementSize = nsnull; - if (nsnull != mMaxElementSizePointer) { - kidMaxElementSize = &maxElementSize; - maxElementSize.width = kidRect.width; - maxElementSize.height = kidRect.height; - } - kidRect.x = x + kidMargin.left; - kidRect.y = mY; - - if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) { - mState.mSkipLeadingWhiteSpace = PR_FALSE; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: fit size=%d,%d", - kidRect.width, kidRect.height)); - mLine->mIsBlock = isBlock; - return PlaceChild(kidRect, kidMetrics, kidMaxElementSize, kidMargin, - NS_FRAME_COMPLETE); - } - - // The child doesn't fit as is; if it's splittable then reflow it - // otherwise return break-before status so that the non-splittable - // child is pushed to the next line. - if (NS_FRAME_IS_SPLITTABLE(splits)) { - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowMappedChild: can't directly fit")); - return ReflowChild(nsnull, PR_FALSE); - } - return NS_LINE_LAYOUT_BREAK_BEFORE; -} - -// Return values: <0 for error -// 0 == NS_LINE_LAYOUT -nsresult -nsLineLayout::ReflowChild(nsIReflowCommand* aReflowCommand, - PRBool aNewChild) -{ - nsIFrame* kidFrame = mState.mKidFrame; - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: attempt frame=%p[%d] mX=%d availWidth=%d", - kidFrame, mState.mKidIndex, - mState.mX, mRightEdge - mState.mX)); - - // Get kid frame's style context - nsIStyleContextPtr kidSC; - nsresult rv = kidFrame->GetStyleContext(mPresContext, kidSC.AssignRef()); - if (NS_OK != rv) { - return rv; - } - - // See if frame belongs in the line. - // XXX absolute positioning - // XXX floating frames - // XXX break-before - const nsStyleDisplay * kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - PRBool isBlock = PR_FALSE; - PRBool isFirstChild = PRBool(kidFrame == mLine->mFirstChild); - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_NONE: - // Make sure the frame remains zero sized. - kidFrame->WillReflow(*mPresContext); - kidFrame->SetRect(nsRect(mState.mX, mY, 0, 0)); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: display=none")); - return NS_LINE_LAYOUT_COMPLETE; - - case NS_STYLE_DISPLAY_INLINE: - break; - - default: - isBlock = PR_TRUE; - if (!isFirstChild) { - // XXX Make sure child is dirty for next time - kidFrame->WillReflow(*mPresContext); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: block requires break-before")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - break; - } - - // Get the available size to reflow the child into - PRBool didBreak = PR_FALSE; - reflow_it_again_sam: - nscoord availWidth = mRightEdge - mState.mX; - nsSize kidAvailSize; - kidAvailSize.width = availWidth; - kidAvailSize.height = mMaxHeight; - const nsStyleSpacing* kidSpacing = (const nsStyleSpacing*) - kidSC->GetStyleData(eStyleStruct_Spacing); - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - if (!mUnconstrainedWidth) { - if (mNoWrap) { - // When our reflow is constrained and we are we are not supposed - // to wrap make sure the child will fit regardless of how much - // space is left. - if (isBlock) { - // Never give a block an infinite width - kidAvailSize.width = mRightEdge - mLeftEdge; - } - else { - kidAvailSize.width = NS_UNCONSTRAINEDSIZE; - } - } - else { - kidAvailSize.width -= kidMargin.left + kidMargin.right; - if (!isFirstChild && (kidAvailSize.width <= 0)) { - // No room. - if (!didBreak && CanBreak()) { - kidFrame = mState.mKidFrame; - didBreak = PR_TRUE; - mPendingBreak = NS_STYLE_CLEAR_NONE; - goto reflow_it_again_sam; - } - - // XXX Make sure child is dirty for next time - kidFrame->WillReflow(*mPresContext); - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: !fit")); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - } - } - - // Reflow the child - mFramesReflowed++; - nsRect kidRect; - nsSize maxElementSize; - nsSize* kidMaxElementSize = nsnull; - nsReflowStatus kidReflowStatus; - if (nsnull != mMaxElementSizePointer) { - kidMaxElementSize = &maxElementSize; - } - nsReflowMetrics kidMetrics(kidMaxElementSize); - - // Get reflow reason set correctly. It's possible that we created a - // child and then decided that we cannot reflow it (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 kidReason = eReflowReason_Resize; - if (nsnull != aReflowCommand) { - kidReason = eReflowReason_Incremental; - } - else if (aNewChild) { - kidReason = eReflowReason_Initial; - } - else { - nsFrameState state; - kidFrame->GetFrameState(state); - if (NS_FRAME_FIRST_REFLOW & state) { - kidReason = eReflowReason_Initial; - } - } - - nsReflowState kidReflowState(kidFrame, *mBlockReflowState.reflowState, - kidAvailSize, kidReason); - kidReflowState.reflowCommand = aReflowCommand; - mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE; - nscoord dx = mState.mX + kidMargin.left; - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: reflowing frame into %d,%d", - kidAvailSize.width, kidAvailSize.height)); - if (isBlock) { - // Calculate top margin by collapsing with previous bottom margin - nscoord negTopMargin; - nscoord posTopMargin; - nsMargin kidMargin; - kidSpacing->CalcMarginFor(kidFrame, kidMargin); - if (kidMargin.top < 0) { - negTopMargin = -kidMargin.top; - posTopMargin = 0; - } else { - negTopMargin = 0; - posTopMargin = kidMargin.top; - } - - // XXX if (nav4_compatability) - // Calculate the previous margin's positive and negative value. - // If the current top margin is not defined by css then just use - // what is cached in the block reflow state. Otherwise if the top - // margin is defined by css then wipe out any synthetic margin. - nscoord prevPos = mBlockReflowState.mPrevPosBottomMargin; - nscoord prevNeg = mBlockReflowState.mPrevNegBottomMargin; - if (eStyleUnit_Null != kidSpacing->mMargin.GetTopUnit()) { - if (mBlockReflowState.mPrevMarginSynthetic) { - prevPos = 0; - prevNeg = 0; - } - } - else { - // When our top margin is not specified by css...act like - // ebina's engine. - if ((nsnull != mLine->mPrevLine) && !mLine->mPrevLine->mIsBlock) { - // Supply a default top margin - const nsStyleFont* styleFont; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)styleFont); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(styleFont->mFont); - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = fm->GetHeight(); - mBlockReflowState.mPrevMarginSynthetic = PR_TRUE; - NS_RELEASE(fm); - } - } - - nscoord maxPos = PR_MAX(prevPos, posTopMargin); - nscoord maxNeg = PR_MAX(prevNeg, negTopMargin); - nscoord topMargin = maxPos - maxNeg; - - // This is no longer a break point - mSavedState.mKidFrame = nsnull; - mBreakFrame = nsnull; - - mY += topMargin; - mBlockReflowState.mY += topMargin; - // XXX tell block what topMargin ended up being so that it can - // undo it if it ends up pushing the line. - - NS_ASSERTION(0 == mPendingBreak, "whoops: uncleared break"); - mSpaceManager->Translate(dx, mY); - kidFrame->WillReflow(*mPresContext); - kidFrame->MoveTo(dx, mY); - rv = mBlock->ReflowBlockChild(kidFrame, mPresContext, - mSpaceManager, kidMetrics, kidReflowState, - kidRect, kidReflowStatus); - mSpaceManager->Translate(-dx, -mY); - - if ((0 == kidRect.width) && (0 == kidRect.height)) { - // When a block child collapses into nothingness we don't apply - // it's margins. - mY -= topMargin; - mBlockReflowState.mY -= topMargin; - } - else { - // XXX if (nav4_compatability) - // If the block frame we just reflowed has no bottom margin as - // specified by css, then we supply our own. - if (eStyleUnit_Null == kidSpacing->mMargin.GetBottomUnit()) { - // ebina's engine uses the height of the font for the bottom margin. - nsIStyleContext* blockSC; - const nsStyleFont* styleFont; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)styleFont); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(styleFont->mFont); - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = fm->GetHeight(); - mBlockReflowState.mPrevMarginSynthetic = PR_TRUE; - NS_RELEASE(fm); - } - else { - // Save away bottom margin information for later - if (kidMargin.bottom < 0) { - mBlockReflowState.mPrevNegBottomMargin = -kidMargin.bottom; - mBlockReflowState.mPrevPosBottomMargin = 0; - } else { - mBlockReflowState.mPrevNegBottomMargin = 0; - mBlockReflowState.mPrevPosBottomMargin = kidMargin.bottom; - } - mBlockReflowState.mPrevMarginSynthetic = PR_FALSE; - } - } - - kidRect.x = dx; - kidRect.y = mY; - kidMetrics.width = kidRect.width; - kidMetrics.height = kidRect.height; - kidMetrics.ascent = kidRect.height; - kidMetrics.descent = 0; - } - else { - // Apply bottom margin speculatively before reflowing the child - nscoord bottomMargin = mBlockReflowState.mPrevPosBottomMargin - - mBlockReflowState.mPrevNegBottomMargin; - if (!mMarginApplied) { - // Before we place the first inline child on this line apply - // the previous block's bottom margin. - mY += bottomMargin; - mBlockReflowState.mY += bottomMargin; - } - - NS_ASSERTION(0 == mPendingBreak, "whoops: uncleared break"); - kidFrame->WillReflow(*mPresContext); - kidFrame->MoveTo(dx, mY); - rv = mBlock->ReflowInlineChild(*this, kidFrame, kidMetrics, - kidReflowState, kidReflowStatus); - - // See if speculative application of the margin should stick - if (!mMarginApplied) { - if (0 == kidMetrics.height) { - // No, undo margin application when we get a zero height child. - mY -= bottomMargin; - mBlockReflowState.mY -= bottomMargin; - } - else { - // Yes, keep the margin application. - mMarginApplied = PR_TRUE; - mBlockReflowState.mPrevPosBottomMargin = 0; - mBlockReflowState.mPrevNegBottomMargin = 0; - // XXX tell block what bottomMargin ended up being so that it can - // undo it if it ends up pushing the line. - } - } - - kidRect.x = dx; - kidRect.y = mY; - kidRect.width = kidMetrics.width; - kidRect.height = kidMetrics.height; - } - if (NS_OK != rv) return rv; - - // See if the child fit - if (kidMetrics.width > kidAvailSize.width) { - if (!isFirstChild) { - if (!didBreak && CanBreak()) { - kidFrame = mState.mKidFrame; - didBreak = PR_TRUE; - mPendingBreak = NS_STYLE_CLEAR_NONE; - goto reflow_it_again_sam; - } - else { - // We are out of room. - // XXX mKidPrevInFlow - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: !fit size=%d,%d", - kidRect.width, kidRect.height)); - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - } - } - - // Non-aware children that take up space act like words; which means - // that space immediately following them must not be skipped over. - if (NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE == mReflowResult) { - if ((kidRect.width != 0) && (kidRect.height != 0)) { - mState.mSkipLeadingWhiteSpace = PR_FALSE; - } - } - - // Now place the child - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::ReflowChild: fit size=%d,%d", - kidRect.width, kidRect.height)); - mLine->mIsBlock = isBlock; - return PlaceChild(kidRect, kidMetrics, kidMaxElementSize, - kidMargin, kidReflowStatus); -} - -nsresult -nsLineLayout::PlaceChild(nsRect& kidRect, - const nsReflowMetrics& kidMetrics, - const nsSize* kidMaxElementSize, - const nsMargin& kidMargin, - nsReflowStatus kidReflowStatus) -{ - nscoord horizontalMargins = 0; - - // Special case to position outside list bullets. - // XXX RTL bullets - PRBool isBullet = PR_FALSE; - if (mBlockReflowState.mListPositionOutside) { - PRBool isFirstChild = PRBool(mState.mKidFrame == mLine->mFirstChild); - PRBool isFirstLine = PRBool(nsnull == mLine->mPrevLine); - if (isFirstChild && isFirstLine) { - nsIFrame* blockPrevInFlow; - mBlock->GetPrevInFlow(blockPrevInFlow); - PRBool isFirstInFlow = PRBool(nsnull == blockPrevInFlow); - if (isFirstInFlow) { - isBullet = PR_TRUE; - // We are placing the first child of the block therefore this - // is the bullet that is being reflowed. The bullet is placed - // in the padding area of this block. Don't worry about - // getting the Y coordinate of the bullet right (vertical - // alignment will take care of that). - - // Compute gap between bullet and inner rect left edge - const nsStyleFont* font; - mBlock->GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); - nsIFontMetrics* fm = mPresContext->GetMetricsFor(font->mFont); - nscoord kidAscent = fm->GetMaxAscent(); - nscoord dx = fm->GetHeight() / 2; // from old layout engine - NS_RELEASE(fm); - - // XXX RTL bullets - kidRect.x = mState.mX - kidRect.width - dx; - mState.mKidFrame->SetRect(kidRect); - } - } - } - if (!isBullet) { - // Place normal in-flow child - mState.mKidFrame->SetRect(kidRect); - - // Advance - // XXX RTL - horizontalMargins = kidMargin.left + kidMargin.right; - nscoord totalWidth = kidMetrics.width + horizontalMargins; - mState.mX += totalWidth; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::PlaceChild: frame=%p[%d] {%d, %d, %d, %d}", - mState.mKidFrame, - mState.mKidIndex, - kidRect.x, kidRect.y, kidRect.width, kidRect.height)); - - if (nsnull != mMaxElementSizePointer) { - // XXX I'm not certain that this is doing the right thing; rethink this - nscoord elementWidth = kidMaxElementSize->width + horizontalMargins; - if (elementWidth > mState.mMaxElementSize.width) { - mState.mMaxElementSize.width = elementWidth; - } - if (kidMetrics.height > mState.mMaxElementSize.height) { - mState.mMaxElementSize.height = kidMetrics.height; - } - } - if (kidMetrics.ascent > mState.mMaxAscent) { - mState.mMaxAscent = kidMetrics.ascent; - } - if (kidMetrics.descent > mState.mMaxDescent) { - mState.mMaxDescent = kidMetrics.descent; - } - SetAscent(mLine->mIsBlock ? 0 : kidMetrics.ascent); - - // Set completion status - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - mLine->mLastContentOffset = mState.mKidIndex; - if (NS_FRAME_IS_COMPLETE(kidReflowStatus)) { - mLine->mLastContentIsComplete = PR_TRUE; - if (mLine->mIsBlock || - (NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER == mReflowResult) || - (NS_STYLE_CLEAR_NONE != mPendingBreak)) { - rv = NS_LINE_LAYOUT_BREAK_AFTER; - if (NS_STYLE_CLEAR_LINE == mPendingBreak) { - mPendingBreak = NS_STYLE_CLEAR_NONE; - } - } - mKidPrevInFlow = nsnull; - } - else { - mLine->mLastContentIsComplete = PR_FALSE; - rv = NS_LINE_LAYOUT_NOT_COMPLETE; - mKidPrevInFlow = mState.mKidFrame; - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::PlaceChild: rv=%d", rv)); - return rv; -} - -nsresult -nsLineLayout::IncrementalReflowFromChild(nsIReflowCommand* aReflowCommand, - nsIFrame* aChildFrame) -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - - mLine->mBounds.x = mState.mX; - mLine->mBounds.y = mY; - mState.mKidFrame = mLine->mFirstChild; - mState.mKidFrameNum = 0; - while (mState.mKidFrameNum < mLine->mChildCount) { - nsresult childReflowStatus; - if (mState.mKidFrame == aChildFrame) { - childReflowStatus = ReflowChild(aReflowCommand, PR_FALSE); - } else { - childReflowStatus = ReflowMappedChild(); - } - - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - -done: - // Perform alignment operations - AlignChildren(); - - // Set final bounds of the line - mLine->mBounds.height = mLineHeight; - mLine->mBounds.width = mState.mX - mLine->mBounds.x; - - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowMapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::SplitLine(PRInt32 aChildReflowStatus) -{ - PRInt32 pushCount = mLine->mChildCount - mState.mKidFrameNum; - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - - if (NS_LINE_LAYOUT_NOT_COMPLETE == aChildReflowStatus) { - // When a line is not complete it indicates that the last child on - // the line reflowed and took some space but wasn't given enough - // space to complete. Sometimes when this happens we will need to - // create a next-in-flow for the child. - nsIFrame* nextInFlow; - mState.mPrevKidFrame->GetNextInFlow(nextInFlow); - if (nsnull == nextInFlow) { - // Create a continuation frame for the child frame and insert it - // into our lines child list. - nsIFrame* nextFrame; - mState.mPrevKidFrame->GetNextSibling(nextFrame); - nsIStyleContext* kidSC; - mState.mPrevKidFrame->GetStyleContext(mPresContext, kidSC); - mState.mPrevKidFrame->CreateContinuingFrame(mPresContext, mBlock, kidSC, - nextInFlow); - NS_RELEASE(kidSC); - if (nsnull == nextInFlow) { - return NS_ERROR_OUT_OF_MEMORY; - } - mState.mPrevKidFrame->SetNextSibling(nextInFlow); - nextInFlow->SetNextSibling(nextFrame); - mNewFrames++; - - // Add new child to our line - mLine->mChildCount++; - - // Set mKidFrame to the new next-in-flow so that we will - // push it when we push children. Increment the number of - // remaining kids now that there is one more. - mState.mKidFrame = nextInFlow; - pushCount++; - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::SplitLine: created next in flow %p", - nextInFlow)); - } - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CHILD_REFLOW, - ("nsLineLayout::SplitLine: pushing %d frames", - pushCount)); - - if (0 != pushCount) { - NS_ASSERTION(nsnull != mState.mKidFrame, "whoops"); - nsLineData* from = mLine; - nsLineData* to = mLine->mNextLine; - if (nsnull != to) { - // Only push into the next line if it's empty; otherwise we can - // end up pushing a frame which is continued into the same frame - // as it's continuation. This causes all sorts of side effects - // so we don't allow it. - if (to->mChildCount != 0) { - nsLineData* insertedLine = new nsLineData(); - from->mNextLine = insertedLine; - to->mPrevLine = insertedLine; - insertedLine->mPrevLine = from; - insertedLine->mNextLine = to; - to = insertedLine; - to->mLastContentOffset = from->mLastContentOffset; - to->mLastContentIsComplete = from->mLastContentIsComplete; - } - } else { - to = new nsLineData(); - to->mPrevLine = from; - from->mNextLine = to; - } - if (nsnull == to) { - return NS_ERROR_OUT_OF_MEMORY; - } - - PRInt32 kidIndexInParent; - mState.mKidFrame->GetContentIndex(kidIndexInParent); - to->mFirstChild = mState.mKidFrame; - to->mChildCount += pushCount; - to->mFirstContentOffset = kidIndexInParent; - - // The to-line is going to be reflowed therefore it's last content - // offset and completion status don't matter. In fact, it's expensive - // to compute them so don't bother. -#ifdef NS_DEBUG - to->mLastContentOffset = -1; - to->mLastContentIsComplete = PRPackedBool(0x255); -#endif - - from->mChildCount -= pushCount; - NS_ASSERTION(0 != from->mChildCount, "bad push"); -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - from->Verify(); - } -#endif -#ifdef NOISY_REFLOW - printf("After push, from-line (%d):\n", pushCount); - from->List(stdout, 1); - printf("After push, to-line:\n"); - to->List(stdout, 1); -#endif - } - - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsLineLayout::SplitLine: returning %d", - aChildReflowStatus)); - return aChildReflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::ReflowMapped() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - - mState.mKidFrame = mLine->mFirstChild; - mState.mKidFrameNum = 0; - while (mState.mKidFrameNum < mLine->mChildCount) { - nsresult childReflowStatus = ReflowMappedChild(); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame->GetNextSibling(mState.mKidFrame); - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowMapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -static PRBool -IsBlock(const nsStyleDisplay* aDisplay) -{ - switch (aDisplay->mDisplay) { - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - return PR_TRUE; - } - return PR_FALSE; -} - -// XXX fix this code to look at the available width and if it's too -// small for the next child then skip the pullup (and return -// BREAK_AFTER status). - -nsresult -nsLineLayout::PullUpChildren() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - nsIFrame* prevKidFrame = mState.mPrevKidFrame; - - nsBlockFrame* currentBlock = mBlock; - nsLineData* line = mLine->mNextLine; - while (nsnull != currentBlock) { - - // Pull children from the next line - while (nsnull != line) { - // Get first child from next line - mState.mKidFrame = line->mFirstChild; - if (nsnull == mState.mKidFrame) { - NS_ASSERTION(0 == line->mChildCount, "bad line list"); - nsLineData* nextLine = line->mNextLine; - nsLineData* prevLine = line->mPrevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - delete line;/* XXX free-list in block-reflow-state? */ - line = nextLine; - continue; - } - - // XXX Avoid the pullup work if the child cannot already fit - // (e.g. it's not splittable and can't fit) - - // XXX change this to use the next-line's mIsBlock when possible - // (make sure push code set it's properly for this to work: only - // from reflow-unmapped) - - // If the child is a block element then if this is not the first - // line in the block or if it's the first line and it's not the - // first child in the line then we cannot pull-up the child. - nsresult rv; - const nsStyleDisplay* kidDisplay; - rv = mState.mKidFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)kidDisplay); - if (NS_OK != rv) { - return rv; - } - if (IsBlock(kidDisplay)) { - if ((nsnull != mLine->mPrevLine) || (0 != mLine->mChildCount)) { - goto done; - } - } - - // Make pulled child part of this line - NS_FRAME_LOG(NS_FRAME_TRACE_PUSH_PULL, - ("nsLineLayout::PullUpChildren: trying to pull frame=%p", - mState.mKidFrame)); - mLine->mChildCount++; - if (0 == --line->mChildCount) { - // Remove empty lines from the list - nsLineData* nextLine = line->mNextLine; - nsLineData* prevLine = line->mPrevLine; - if (nsnull != prevLine) prevLine->mNextLine = nextLine; - if (nsnull != nextLine) nextLine->mPrevLine = prevLine; - delete line;/* XXX free-list in block-reflow-state? */ - line = nextLine; - } - else { - // Repair the first content offset of the line. The first - // child of the line's index-in-parent should be the line's - // new first content offset. - mState.mKidFrame->GetNextSibling(line->mFirstChild); - PRInt32 indexInParent; - line->mFirstChild->GetContentIndex(indexInParent); - line->mFirstContentOffset = indexInParent; -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - line->Verify(); - } -#endif - } - - // Try to reflow it like any other mapped child - nsresult childReflowStatus = ReflowMappedChild(); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidIndex++; - mState.mKidFrameNum++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidIndex++; - mState.mKidFrameNum++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - - // Grab the block's next in flow - nsIFrame* nextInFlow; - currentBlock->GetNextInFlow(nextInFlow); - currentBlock = (nsBlockFrame*)nextInFlow; - if (nsnull != currentBlock) { - line = currentBlock->GetFirstLine(); - } - } - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from PullUpChildren"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::CreateFrameFor(nsIContent* aKid) -{ - nsIStyleContextPtr kidSC = - mPresContext->ResolveStyleContextFor(aKid, mBlock); // XXX bad API - if (nsnull == kidSC) { - return NS_ERROR_OUT_OF_MEMORY; - } - const nsStylePosition* kidPosition = (const nsStylePosition*) - kidSC->GetStyleData(eStyleStruct_Position); - const nsStyleDisplay* kidDisplay = (const nsStyleDisplay*) - kidSC->GetStyleData(eStyleStruct_Display); - - // Check whether it wants to floated or absolutely positioned - PRBool isBlock = PR_FALSE; - nsIFrame* kidFrame; - nsresult rv; - if (NS_STYLE_POSITION_ABSOLUTE == kidPosition->mPosition) { - rv = nsAbsoluteFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if (NS_STYLE_FLOAT_NONE != kidDisplay->mFloats) { - rv = nsPlaceholderFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if ((NS_STYLE_OVERFLOW_SCROLL == kidDisplay->mOverflow) || - (NS_STYLE_OVERFLOW_AUTO == kidDisplay->mOverflow)) { - rv = NS_NewScrollFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - } - else if (nsnull == mKidPrevInFlow) { - // Create initial frame for the child - nsIContentDelegate* kidDel; - switch (kidDisplay->mDisplay) { - case NS_STYLE_DISPLAY_NONE: - rv = nsFrame::NewFrame(&kidFrame, aKid, mBlock); - if (NS_OK == rv) { - kidFrame->SetStyleContext(mPresContext, kidSC); - } - break; - - case NS_STYLE_DISPLAY_BLOCK: - case NS_STYLE_DISPLAY_LIST_ITEM: - isBlock = PR_TRUE; - // FALL THROUGH - default: - kidDel = aKid->GetDelegate(mPresContext); - rv = kidDel->CreateFrame(mPresContext, aKid, mBlock, kidSC, kidFrame); - NS_RELEASE(kidDel); - break; - } - } else { - // Since kid has a prev-in-flow, use that to create the next - // frame. - rv = mKidPrevInFlow->CreateContinuingFrame(mPresContext, mBlock, kidSC, - kidFrame); - NS_ASSERTION(0 == mLine->mChildCount, "bad continuation"); - } - if (NS_OK != rv) { - return rv; - } - if (NS_OK == rv) { - // Wrap the frame in a view if necessary - rv = nsHTMLBase::CreateViewForFrame(mPresContext, kidFrame, kidSC, - PR_FALSE); - if (NS_OK != rv) { - return rv; - } - } - - mState.mKidFrame = kidFrame; - mNewFrames++; - - if (isBlock && (0 != mLine->mChildCount)) { - // When we are not at the start of a line we need to break - // before a block element. - return NS_LINE_LAYOUT_BREAK_BEFORE; - } - - return rv; -} - -nsresult -nsLineLayout::ReflowUnmapped() -{ - nsresult reflowStatus = NS_LINE_LAYOUT_COMPLETE; - for (;;) { - nsIContentPtr kid = mBlockContent->ChildAt(mState.mKidIndex); - if (kid.IsNull()) { - break; - } - - // Create a frame for the new content - nsresult rv = CreateFrameFor(kid); - if (rv < 0) { - reflowStatus = rv; - goto done; - } - - // Add frame to our list - if (nsnull != mState.mPrevKidFrame) { - mState.mPrevKidFrame->SetNextSibling(mState.mKidFrame); - } - if (0 == mLine->mChildCount) { - mLine->mFirstChild = mState.mKidFrame; - mBlock->SetFirstChild(mState.mKidFrame); - } - mLine->mChildCount++; - - nsresult childReflowStatus; - if (rv == NS_LINE_LAYOUT_BREAK_BEFORE) { - // If we break before a frame is even supposed to layout then we - // need to split the line. - childReflowStatus = rv; - - // XXX Mark new frame dirty so it gets reflow later on - mState.mKidFrame->WillReflow(*mPresContext); - goto split_line; - } - - // Reflow new child frame - childReflowStatus = ReflowChild(nsnull, PR_TRUE); - if (childReflowStatus < 0) { - reflowStatus = childReflowStatus; - goto done; - } - switch (childReflowStatus) { - default: - case NS_LINE_LAYOUT_COMPLETE: - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - mState.mKidIndex++; - break; - - case NS_LINE_LAYOUT_NOT_COMPLETE: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_BEFORE: - reflowStatus = childReflowStatus; - goto split_line; - - case NS_LINE_LAYOUT_BREAK_AFTER: - reflowStatus = childReflowStatus; - mState.mPrevKidFrame = mState.mKidFrame; - mState.mKidFrame = nsnull; - mState.mKidFrameNum++; - mState.mKidIndex++; - - split_line: - reflowStatus = SplitLine(childReflowStatus); - goto done; - } - } - NS_ASSERTION(nsnull == mLine->mNextLine, "bad line list"); - -done: - NS_ASSERTION(((reflowStatus < 0) || - (reflowStatus == NS_LINE_LAYOUT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_NOT_COMPLETE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_BEFORE) || - (reflowStatus == NS_LINE_LAYOUT_BREAK_AFTER)), - "bad return status from ReflowUnmapped"); - return reflowStatus; -} - -//---------------------------------------------------------------------- - -nsresult -nsLineLayout::ReflowLine() -{ - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("enter nsLineLayout::ReflowLine: childCount=%d {%d, %d, %d, %d}", - mLine->mChildCount, - mLine->mBounds.x, mLine->mBounds.y, - mLine->mBounds.width, mLine->mBounds.height)); - - nsresult rv = NS_LINE_LAYOUT_COMPLETE; - - mLine->mBounds.x = mState.mX; - mLine->mBounds.y = mY; - mOldChildCount = mLine->mChildCount; - - // Reflow the mapped frames - if (0 != mLine->mChildCount) { - rv = ReflowMapped(); - if (rv < 0) return rv; - } - - // Pull-up any frames from the next line - if (NS_LINE_LAYOUT_COMPLETE == rv) { - if (nsnull != mLine->mNextLine) { - rv = PullUpChildren(); - if (rv < 0) return rv; - } - - // Try reflowing any unmapped children - if (NS_LINE_LAYOUT_COMPLETE == rv) { - if (nsnull == mLine->mNextLine) { - rv = ReflowUnmapped(); - if (rv < 0) return rv; - } - } - } - - // Perform alignment operations - AlignChildren(); - - // Set final bounds of the line - mLine->mBounds.height = mLineHeight; - mLine->mBounds.width = mState.mX - mLine->mBounds.x; - -#ifdef NS_DEBUG - if (nsIFrame::GetVerifyTreeEnable()) { - mLine->Verify(); - } -#endif - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("exit nsLineLayout::ReflowLine: childCount=%d {%d, %d, %d, %d}", - mLine->mChildCount, - mLine->mBounds.x, mLine->mBounds.y, - mLine->mBounds.width, mLine->mBounds.height)); - return rv; -} - -void -nsLineLayout::AlignChildren() -{ - NS_PRECONDITION(mLine->mChildCount == mState.mKidFrameNum, "bad line reflow"); - - // Block lines don't require (or allow!) alignment - if (mLine->mIsBlock) { - mLineHeight = mState.mMaxAscent + mState.mMaxDescent; - } - else { - // Avoid alignment when we didn't actually reflow any frames and we - // also didn't change the number of frames we had (which means the - // pullup code didn't pull anything up). When this happens it means - // that nothing changed which means that we can avoid the alignment - // work. - if ((0 == mFramesReflowed) && (mOldChildCount == mLine->mChildCount)) { - mLineHeight = mLine->mBounds.height; - } - } - - nsIStyleContextPtr blockSC; - mBlock->GetStyleContext(mPresContext, blockSC.AssignRef()); - const nsStyleFont* blockFont = (const nsStyleFont*) - blockSC->GetStyleData(eStyleStruct_Font); - const nsStyleText* blockText = (const nsStyleText*) - blockSC->GetStyleData(eStyleStruct_Text); - const nsStyleDisplay* blockDisplay = (const nsStyleDisplay*) - blockSC->GetStyleData(eStyleStruct_Display); - - // First vertically align the children on the line; this will - // compute the actual line height for us. - if (!mLine->mIsBlock) { - mLineHeight = - nsCSSLayout::VerticallyAlignChildren(mPresContext, mBlock, blockFont, - mY, - mLine->mFirstChild, - mLine->mChildCount, - mAscents, mState.mMaxAscent); - } - - // Now horizontally place the children - nsCSSLayout::HorizontallyPlaceChildren(mPresContext, mBlock, - blockText->mTextAlign, - blockDisplay->mDirection, - mLine->mFirstChild, - mLine->mChildCount, - mState.mX - mLeftEdge, - mMaxWidth); - - // Last, apply relative positioning - nsCSSLayout::RelativePositionChildren(mPresContext, mBlock, - mLine->mFirstChild, - mLine->mChildCount); -} diff --git a/mozilla/layout/html/base/src/nsLineLayout.h b/mozilla/layout/html/base/src/nsLineLayout.h deleted file mode 100644 index 34bc57051e2..00000000000 --- a/mozilla/layout/html/base/src/nsLineLayout.h +++ /dev/null @@ -1,248 +0,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 - * Version 1.0 (the "NPL"); you may not use this file except in - * compliance with the NPL. You may obtain a copy of the NPL at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the NPL is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL - * for the specific language governing rights and limitations under the - * NPL. - * - * The Initial Developer of this code under the NPL is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All Rights - * Reserved. - */ -#ifndef nsLineLayout_h___ -#define nsLineLayout_h___ - -#include "nsIFrame.h" -#include "nsCoord.h" -#include "nsSize.h" -#include "nsVoidArray.h" - -class nsIPresContext; -class nsISpaceManager; -class nsBlockFrame; -struct nsBlockReflowState; -struct nsLineLayout; - -/* d76e29b0-ff56-11d1-89e7-006008911b81 */ -#define NS_IINLINE_FRAME_IID \ -{0xd76e29b0, 0xff56, 0x11d1, {0x89, 0xe7, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}} - -/** - * Interface to "inline frames". Inline frames are those that are aware - * of html line layout. - * - * Note that this interface does not expose AddRef/Release (like all frame - * interfaces) - */ -class nsIInlineFrame : private nsISupports { -public: - NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0; - - NS_IMETHOD ReflowInline(nsLineLayout& aLineLayout, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) = 0; -}; - -//---------------------------------------------------------------------- - -/** - * Persistent per-line data - */ -struct nsLineData { - nsLineData(); - ~nsLineData(); - - nsIFrame* GetLastChild(); - nsresult Verify(PRBool aFinalCheck = PR_TRUE) const; - void List(FILE* out = stdout, PRInt32 aIndent = 0) const; - void UnlinkLine(); - PRIntn GetLineNumber() const; - - nsLineData* mNextLine; - nsLineData* mPrevLine; - nsIFrame* mFirstChild; - PRInt32 mChildCount; - PRInt32 mFirstContentOffset; - PRInt32 mLastContentOffset; - nsRect mBounds; - PRPackedBool mLastContentIsComplete; - PRPackedBool mIsBlock; - nsVoidArray* mFloaters; // placeholder frames for below current line floaters -}; - -//---------------------------------------------------------------------- - -/** - * Transient state used during line reflow. - */ - -// State used during line layout that may need to be rewound because -// of an inconvenient word break. -struct nsLineLayoutState { - // The next x coordinate to place the child frame - nscoord mX; - - // This is true if the next frame to reflow should skip over leading - // whitespace. - PRBool mSkipLeadingWhiteSpace; - - // The column number when pre-formatting (for tab spacing) - PRInt32 mColumn; - - // The child frame being considered for reflow - nsIFrame* mKidFrame; - - // The previous child frame just reflowed - nsIFrame* mPrevKidFrame; - - // The child frame's content index-in-parent - PRInt32 mKidIndex; - - // The child frame number within this line - PRInt32 mKidFrameNum; - - // Current line values values - nsSize mMaxElementSize; - nscoord mMaxAscent; - nscoord mMaxDescent; -}; - -struct nsLineLayout { - nsLineLayout(nsBlockReflowState& aState); - ~nsLineLayout(); - - nsresult Initialize(nsBlockReflowState& aState, nsLineData* aLine); - - void SetReflowSpace(nsRect& aAvailableSpaceRect); - - nsresult ReflowLine(); - - nsresult IncrementalReflowFromChild(nsIReflowCommand* aReflowCommand, - nsIFrame* aChildFrame); - - void AtSpace(); - - void AtWordStart(nsIFrame* aFrame, nscoord aX); - - PRBool SkipLeadingWhiteSpace() { - return mState.mSkipLeadingWhiteSpace; - } - - void SetSkipLeadingWhiteSpace(PRBool aSkip) { - mState.mSkipLeadingWhiteSpace = aSkip; - } - - PRIntn GetColumn() { - return mState.mColumn; - } - - void SetColumn(PRIntn aNewColumn) { - mState.mColumn = aNewColumn; - } - - // A value set by line-layout cognizant frames. Frames that are not - // aware of line layout leave the value unchanged and can thus be - // detected by the line-layout algorithm. - PRInt32 mReflowResult; - - // The presentation context - nsIPresContext* mPresContext; - - // The block behind the line - nsBlockFrame* mBlock; - nsBlockReflowState& mBlockReflowState; - nsISpaceManager* mSpaceManager; - nsIContent* mBlockContent; - PRBool mNoWrap; - - // The line we are reflowing - nsLineData* mLine; - nsIFrame* mKidPrevInFlow; - - // Whenever the line layout creates a frame this slot is incremented - PRIntn mNewFrames; - PRIntn mFramesReflowed; - PRIntn mOldChildCount; - - nsLineLayoutState mState; - nsLineLayoutState mSavedState; - - // The current breakable point in the line. If a line-break is - // requested then this is where the line will break at. - nsIFrame* mBreakFrame; - nscoord mBreakX; - PRUint8 mPendingBreak; - - // XXX ick - // This is set by the block code when it updates the available - // reflow area when a floater is placed. - PRBool mReflowDataChanged; - PRPackedBool mMustReflowMappedChildren; - - PRPackedBool mUnconstrainedWidth; - PRPackedBool mUnconstrainedHeight; - PRPackedBool mMarginApplied; - - nscoord mY; - nscoord mLineHeight; - nscoord mMaxWidth; - nscoord mMaxHeight; - nsSize* mMaxElementSizePointer; - nscoord mLeftEdge; - nscoord mRightEdge; - - nscoord* mAscents; - nscoord mAscentBuf[20]; - nscoord mMaxAscents; - -protected: - nsresult SetAscent(nscoord aAscent); - - nsresult ReflowMappedChild(); - - nsresult ReflowChild(nsIReflowCommand* aReflowCommand, PRBool aNewChild); - - nsresult PlaceChild(nsRect& kidRect, - const nsReflowMetrics& kidMetrics, - const nsSize* kidMaxElementSize, - const nsMargin& kidMargin, - nsReflowStatus kidReflowStatus); - - nsresult ReflowMapped(); - - nsresult SplitLine(PRInt32 aChildReflowStatus); - - nsresult PushChildren(); - - nsresult CreateNextInFlow(nsIFrame* aFrame); - - nsresult PullUpChildren(); - - nsresult CreateFrameFor(nsIContent* aKid); - - nsresult ReflowUnmapped(); - - void AlignChildren(); - - PRBool CanBreak(); -}; - -// Value's for nsLineLayout.mReflowResult -#define NS_LINE_LAYOUT_REFLOW_RESULT_NOT_AWARE 0 -#define NS_LINE_LAYOUT_REFLOW_RESULT_AWARE 1 -#define NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER 2 - -// Return value's from nsLineLayout reflow methods -#define NS_LINE_LAYOUT_COMPLETE 0 -#define NS_LINE_LAYOUT_NOT_COMPLETE 1 -#define NS_LINE_LAYOUT_BREAK_BEFORE 2 -#define NS_LINE_LAYOUT_BREAK_AFTER 3 - -#endif /* nsLineLayout_h___ */ diff --git a/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp b/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp index 5ce07ccbb92..d9c74c4c9ea 100644 --- a/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp +++ b/mozilla/layout/html/base/src/nsPlaceholderFrame.cpp @@ -23,8 +23,7 @@ #include "nsIStyleContext.h" #include "nsCSSLayout.h" #include "nsIView.h" - -static NS_DEFINE_IID(kIFloaterContainerIID, NS_IFLOATERCONTAINER_IID); +#include "nsHTMLIIDs.h" nsresult nsPlaceholderFrame::NewFrame(nsIFrame** aInstancePtrResult, @@ -112,7 +111,7 @@ nsPlaceholderFrame::Reflow(nsIPresContext* aPresContext, } // Notify our containing block that there's a new floater - container->AddFloater(aPresContext, mAnchoredItem, this); + container->AddFloater(aPresContext, aReflowState, mAnchoredItem, this); } else { // XXX This causes anchored-items sizes to get fixed up; this is @@ -125,7 +124,8 @@ nsPlaceholderFrame::Reflow(nsIPresContext* aPresContext, mAnchoredItem->WillReflow(*aPresContext); mAnchoredItem->Reflow(aPresContext, desiredSize, reflowState, aStatus); mAnchoredItem->SizeTo(desiredSize.width, desiredSize.height); - container->PlaceFloater(aPresContext, mAnchoredItem, this); + +//XXXdeprecated container->PlaceFloater(aPresContext, mAnchoredItem, this); mAnchoredItem->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); } diff --git a/mozilla/layout/html/base/src/nsRootPart.cpp b/mozilla/layout/html/base/src/nsRootPart.cpp index f10a338a329..a45ab36b6f1 100644 --- a/mozilla/layout/html/base/src/nsRootPart.cpp +++ b/mozilla/layout/html/base/src/nsRootPart.cpp @@ -282,7 +282,7 @@ void RootContentFrame::CreateFirstChild(nsIPresContext* aPresContext) } // XXX Hack -#define PAGE_SPACING 100 +#define PAGE_SPACING_TWIPS 100 NS_METHOD RootContentFrame::Reflow(nsIPresContext* aPresContext, nsReflowMetrics& aDesiredSize, @@ -342,35 +342,45 @@ NS_METHOD RootContentFrame::Reflow(nsIPresContext* aPresContext, // Resize our frames if (nsnull != mFirstChild) { if (aPresContext->IsPaginated()) { - nscoord y = PAGE_SPACING; + nscoord y = PAGE_SPACING_TWIPS; nsReflowMetrics kidSize(aDesiredSize.maxElementSize); + + // Compute the size of each page and the x coordinate within + // ourselves that the pages will be placed at. nsSize pageSize(aPresContext->GetPageWidth(), aPresContext->GetPageHeight()); + nsIDeviceContext *dx = aPresContext->GetDeviceContext(); + PRInt32 extra = aReflowState.maxSize.width - PAGE_SPACING_TWIPS*2 - + pageSize.width - NS_TO_INT_ROUND(dx->GetScrollBarWidth()); + NS_RELEASE(dx); + + // Note: nscoord is an unsigned type so don't combine these + // two statements or the extra will be promoted to unsigned + // and the >0 won't work! + nscoord x = PAGE_SPACING_TWIPS; + if (extra > 0) { + x += extra / 2; + } // Tile the pages vertically for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) { // Reflow the page - nsReflowState kidReflowState(kidFrame, aReflowState, pageSize, reflowReason); + nsReflowState kidReflowState(kidFrame, aReflowState, pageSize, + reflowReason); nsReflowStatus status; - // Place and size the page. If the page is narrower than our max width then - // center it horizontally - nsIDeviceContext *dx = aPresContext->GetDeviceContext(); - PRInt32 extra = aReflowState.maxSize.width - kidSize.width - - NS_TO_INT_ROUND(dx->GetScrollBarWidth()); - NS_RELEASE(dx); - nscoord x = extra > 0 ? extra / 2 : 0; - + // Place and size the page. If the page is narrower than our + // max width then center it horizontally kidFrame->WillReflow(*aPresContext); kidFrame->MoveTo(x, y); - status = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState); - + status = ReflowChild(kidFrame, aPresContext, kidSize, + kidReflowState); kidFrame->SetRect(nsRect(x, y, kidSize.width, kidSize.height)); kidFrame->DidReflow(*aPresContext, NS_FRAME_REFLOW_FINISHED); y += kidSize.height; // Leave a slight gap between the pages - y += PAGE_SPACING; + y += PAGE_SPACING_TWIPS; // Is the page complete? nsIFrame* kidNextInFlow; @@ -404,8 +414,14 @@ NS_METHOD RootContentFrame::Reflow(nsIPresContext* aPresContext, } // Return our desired size - aDesiredSize.width = aReflowState.maxSize.width; aDesiredSize.height = y; + if (aDesiredSize.height < aReflowState.maxSize.height) { + aDesiredSize.height = aReflowState.maxSize.height; + } + aDesiredSize.width = PAGE_SPACING_TWIPS*2 + pageSize.width; + if (aDesiredSize.width < aReflowState.maxSize.width) { + aDesiredSize.width = aReflowState.maxSize.width; + } } else { // Allow the frame to be as wide as our max width, and as high diff --git a/mozilla/layout/html/base/src/nsScrollFrame.cpp b/mozilla/layout/html/base/src/nsScrollFrame.cpp index fd0f4ec4047..9d673b1d351 100644 --- a/mozilla/layout/html/base/src/nsScrollFrame.cpp +++ b/mozilla/layout/html/base/src/nsScrollFrame.cpp @@ -100,7 +100,8 @@ nsScrollBodyFrame::Reflow(nsIPresContext* aPresContext, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { - NS_FRAME_TRACE_MSG(("enter nsScrollBodyFrame::Reflow: maxSize=%d,%d", + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("enter nsScrollBodyFrame::Reflow: maxSize=%d,%d", aReflowState.maxSize.width, aReflowState.maxSize.height)); @@ -259,9 +260,9 @@ nsScrollBodyFrame::Reflow(nsIPresContext* aPresContext, PostReflowCheck(aStatus); #endif - NS_FRAME_TRACE_MSG( - ("exit nsScrollBodyFrame::Reflow: status=%d width=%d height=%d", - aStatus, aDesiredSize.width, aDesiredSize.height)); + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("exit nsScrollBodyFrame::Reflow: status=%d width=%d height=%d", + aStatus, aDesiredSize.width, aDesiredSize.height)); return NS_OK; } @@ -324,7 +325,8 @@ nsScrollInnerFrame::Reflow(nsIPresContext* aPresContext, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { - NS_FRAME_TRACE_MSG(("enter nsScrollInnerFrame::Reflow: maxSize=%d,%d", + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("enter nsScrollInnerFrame::Reflow: maxSize=%d,%d", aReflowState.maxSize.width, aReflowState.maxSize.height)); @@ -406,7 +408,7 @@ nsScrollInnerFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.height = aReflowState.maxSize.height; } - NS_FRAME_TRACE_MSG( + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, ("exit nsScrollInnerFrame::Reflow: status=%d width=%d height=%d", aStatus, aDesiredSize.width, aDesiredSize.height)); return NS_OK; @@ -457,7 +459,8 @@ nsScrollOuterFrame::Reflow(nsIPresContext* aPresContext, const nsReflowState& aReflowState, nsReflowStatus& aStatus) { - NS_FRAME_TRACE_MSG(("enter nsScrollOuterFrame::Reflow: maxSize=%d,%d", + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, + ("enter nsScrollOuterFrame::Reflow: maxSize=%d,%d", aReflowState.maxSize.width, aReflowState.maxSize.height)); @@ -521,7 +524,7 @@ nsScrollOuterFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; - NS_FRAME_TRACE_MSG( + NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, ("exit nsScrollOuterFrame::Reflow: status=%d width=%d height=%d", aStatus, aDesiredSize.width, aDesiredSize.height)); return NS_OK; diff --git a/mozilla/layout/html/base/src/nsSpacerPart.cpp b/mozilla/layout/html/base/src/nsSpacerPart.cpp index 4db1cdb8696..8d72c483a08 100644 --- a/mozilla/layout/html/base/src/nsSpacerPart.cpp +++ b/mozilla/layout/html/base/src/nsSpacerPart.cpp @@ -17,7 +17,9 @@ */ #include "nsHTMLParts.h" #include "nsHTMLTagContent.h" -#include "nsBlockFrame.h" +#include "nsFrame.h" +#include "nsIInlineReflow.h" +#include "nsCSSLineLayout.h" #include "nsHTMLIIDs.h" #include "nsIPresContext.h" #include "nsIPresShell.h" @@ -31,15 +33,19 @@ #define TYPE_LINE 1 // line-break + vertical space #define TYPE_IMAGE 2 // acts like a sized image with nothing to see -class SpacerFrame : public nsFrame -{ +class SpacerFrame : public nsFrame, nsIInlineReflow { public: SpacerFrame(nsIContent* aContent, nsIFrame* aParentFrame); - NS_IMETHOD Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + // nsIInlineReflow + NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout); + NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aDesiredSize, + const nsReflowState& aReflowState); + protected: virtual ~SpacerFrame(); }; @@ -76,34 +82,36 @@ SpacerFrame::~SpacerFrame() { } -NS_METHOD SpacerFrame::Reflow(nsIPresContext* aPresContext, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_IMETHODIMP +SpacerFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) { - // Get cached state for containing block frame - nsLineLayout* lineLayoutState = nsnull; - nsBlockReflowState* state = - nsBlockFrame::FindBlockReflowState(aPresContext, this); - if (nsnull != state) { - lineLayoutState = state->mCurrentLine; + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; } - - // By default, we have no area - aDesiredSize.width = 0; - aDesiredSize.height = 0; - aDesiredSize.ascent = 0; - aDesiredSize.descent = 0; - - if (nsnull == state) { - // We don't do anything unless we are in a block container somewhere - aStatus = NS_FRAME_COMPLETE; + if (aIID.Equals(kIInlineReflowIID)) { + *aInstancePtrResult = (void*) ((nsIInlineReflow*)this); return NS_OK; } + return nsFrame::QueryInterface(aIID, aInstancePtrResult); +} + +NS_IMETHODIMP +SpacerFrame::InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState) +{ + nsresult rv = NS_INLINE_REFLOW_COMPLETE; + + // By default, we have no area + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; nscoord width = 0; nscoord height = 0; - SpacerPart* part = (SpacerPart*) mContent; + SpacerPart* part = (SpacerPart*) mContent;/* XXX decouple */ PRUint8 type = part->GetType(); nsContentAttr ca; if (type != TYPE_IMAGE) { @@ -128,34 +136,41 @@ NS_METHOD SpacerFrame::Reflow(nsIPresContext* aPresContext, } } - float p2t = aPresContext->GetPixelsToTwips(); + float p2t = aLineLayout.mPresContext->GetPixelsToTwips(); switch (type) { case TYPE_WORD: if (0 != width) { - aDesiredSize.width = nscoord(width * p2t); + aMetrics.width = nscoord(width * p2t); } break; case TYPE_LINE: if (0 != width) { - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = - NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER; - lineLayoutState->mPendingBreak = NS_STYLE_CLEAR_LINE; - } - aDesiredSize.height = nscoord(width * p2t); - aDesiredSize.ascent = aDesiredSize.height; + rv = NS_INLINE_REFLOW_LINE_BREAK_AFTER; + aMetrics.height = nscoord(width * p2t); + aMetrics.ascent = aMetrics.height; } break; case TYPE_IMAGE: - aDesiredSize.width = nscoord(width * p2t); - aDesiredSize.height = nscoord(height * p2t); - aDesiredSize.ascent = aDesiredSize.height; + aMetrics.width = nscoord(width * p2t); + aMetrics.height = nscoord(height * p2t); + aMetrics.ascent = aMetrics.height; break; } - aStatus = NS_FRAME_COMPLETE; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = aMetrics.width; + aMetrics.maxElementSize->height = aMetrics.height; + } + + return rv; +} + +NS_IMETHODIMP +SpacerFrame::FindTextRuns(nsCSSLineLayout& aLineLayout) +{ + aLineLayout.EndTextRun(); return NS_OK; } diff --git a/mozilla/layout/html/base/src/nsTextContent.cpp b/mozilla/layout/html/base/src/nsTextContent.cpp index d3f5d2c0ca0..02eae2b6312 100644 --- a/mozilla/layout/html/base/src/nsTextContent.cpp +++ b/mozilla/layout/html/base/src/nsTextContent.cpp @@ -18,6 +18,8 @@ #include "nsHTMLParts.h" #include "nsCRT.h" #include "nsSplittableFrame.h" +#include "nsIInlineReflow.h" +#include "nsCSSLineLayout.h" #include "nsHTMLContent.h" #include "nsString.h" #include "nsIPresContext.h" @@ -32,7 +34,6 @@ #include "nsIViewManager.h" #include "nsITimerCallback.h" #include "nsITimer.h" -#include "nsBlockFrame.h" #include "prtime.h" #include "nsVoidArray.h" #include "prprf.h" @@ -57,7 +58,7 @@ PRBool IsInRange(nsIContent * aStart, nsIContent * aEnd, nsIContent * aContent); #endif // XXX TODO: -// 0. tune justified text +// 0. re-implement justified text // 1. add in a rendering method that can render justified text // 2. text renderer should negotiate with rendering context/font // metrics to see what it can handle; for example, if the renderer can @@ -65,6 +66,9 @@ PRBool IsInRange(nsIContent * aStart, nsIContent * aEnd, nsIContent * aContent); // etc, then the text renderer should let the rc do the work; // otherwise there should be XP fallback code here. +// XXX TODO: +// implement nsIFrame::Reflow + // XXX Speedup ideas // 1. justified text can use word width information during resize reflows // 2. when we are doing an unconstrained reflow we know we are going to @@ -113,37 +117,35 @@ public: nsVoidArray mFrames; }; -class TextFrame : public nsSplittableFrame { +class TextFrame : public nsSplittableFrame, nsIInlineReflow { public: TextFrame(nsIContent* aContent, nsIFrame* aParentFrame); + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + // nsIFrame NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - - NS_IMETHOD Reflow(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus); - - NS_IMETHOD GetReflowMetrics(nsIPresContext* aPresContext, - nsReflowMetrics& aMetrics); - - NS_IMETHOD JustifyReflow(nsIPresContext* aCX, - nscoord aAvailableSpace); - NS_IMETHOD GetCursorAt(nsIPresContext& aPresContext, const nsPoint& aPoint, nsIFrame** aFrame, PRInt32& aCursor); - NS_IMETHOD ContentChanged(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aChild, nsISupports* aSubContent); - NS_IMETHOD List(FILE* out, PRInt32 aIndent) const; + NS_IMETHOD ListTag(FILE* out) const; + // nsIInlineReflow + NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout); + NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState); + + // TextFrame methods PRInt32 GetPosition(nsIPresContext& aCX, nsGUIEvent* aEvent, nsIFrame * aNewFrame); @@ -172,26 +174,18 @@ protected: const nsRect& aDirtyRect, nscoord dx, nscoord dy); - void PaintJustifiedText(nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nscoord dx, nscoord dy); + nsInlineReflowStatus ReflowPre(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState, + const nsStyleFont& aFont, + PRInt32 aStartingOffset); - nsReflowStatus ReflowPre(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsSize& aMaxSize, - nsSize* aMaxElementSize, - const nsStyleFont& aFont, - PRInt32 aStartingOffset, - nsLineLayout* aLineState); - - nsReflowStatus ReflowNormal(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsSize& aMaxSize, - nsSize* aMaxElementSize, - const nsStyleFont& aFont, - const nsStyleText& aTextStyle, - PRInt32 aStartingOffset, - nsLineLayout* aLineState); + nsInlineReflowStatus ReflowNormal(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState, + const nsStyleFont& aFontStyle, + const nsStyleText& aTextStyle, + PRInt32 aStartingOffset); public: PRInt32 mContentOffset; @@ -200,13 +194,6 @@ public: // XXX need a better packing PRUint32 mFlags; PRUint32 mColumn; - - // When this text frame is justified, this pointer is not null - // and points to data about each word/space in the text - PRUint32* mWords; -#ifdef DEBUG_JUSTIFY - PRInt32 mNumWords; -#endif }; // Flag information used by rendering code. This information is @@ -221,6 +208,7 @@ public: #define TEXT_GET_TAB_COUNT(_mf) ((_mf) >> 5) #define TEXT_SET_TAB_COUNT(_mf,_tabs) (_mf) = (_mf) | ((_tabs)<< 5) +#if XXX // mWords bit definitions #define WORD_IS_WORD 0x80000000L #define WORD_IS_SPACE 0x00000000L @@ -235,6 +223,7 @@ public: ((PRIntn) (((_wi) & WORD_LENGTH_MASK)/* >> WORD_LENGTH_SHIFT*/)) #define GET_WORD_WIDTH(_wi) \ ((nscoord) ((PRUint32(_wi) & WORD_WIDTH_MASK) >> WORD_WIDTH_SHIFT)) +#endif class Text : public nsHTMLContent, public nsIDOMText { public: @@ -411,9 +400,20 @@ TextFrame::~TextFrame() // Release text timer when the last text frame is gone gTextBlinker = nsnull; } - if (nsnull != mWords) { - delete[] mWords; +} + +NS_IMETHODIMP +TextFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; } + if (aIID.Equals(kIInlineReflowIID)) { + *aInstancePtrResult = (void*) ((nsIInlineReflow*)this); + return NS_OK; + } + return nsFrame::QueryInterface(aIID, aInstancePtrResult); } NS_METHOD TextFrame::GetCursorAt(nsIPresContext& aPresContext, @@ -467,32 +467,25 @@ NS_METHOD TextFrame::Paint(nsIPresContext& aPresContext, // Set font and color aRenderingContext.SetColor(color->mColor); aRenderingContext.SetFont(font->mFont); - - if (nsnull != mWords) { - PaintJustifiedText(aRenderingContext, aDirtyRect, 0, 0); - if (font->mThreeD) { - nscoord onePixel = nscoord(1.0f * aPresContext.GetPixelsToTwips()); - aRenderingContext.SetColor(color->mBackgroundColor); - PaintJustifiedText(aRenderingContext, aDirtyRect, onePixel, onePixel); - } - return NS_OK; - } PaintRegularText(aPresContext, aRenderingContext, aDirtyRect, 0, 0); - //nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect); + +#if XXX if (font->mThreeD) { nscoord onePixel = nscoord(1.0f * aPresContext.GetPixelsToTwips()); aRenderingContext.SetColor(color->mBackgroundColor); PaintRegularText(aPresContext, aRenderingContext, aDirtyRect, onePixel, onePixel); } +#endif } return NS_OK; } -void TextFrame::PaintRegularText(nsIPresContext& aPresContext, - nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nscoord dx, nscoord dy) +void +TextFrame::PaintRegularText(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nscoord dx, nscoord dy) { // Skip leading space if necessary Text* txt = (Text*) mContent; @@ -660,124 +653,24 @@ void TextFrame::PaintRegularText(nsIPresContext& aPresContext, } } -void TextFrame::PaintJustifiedText(nsIRenderingContext& aRenderingContext, - const nsRect& aDirtyRect, - nscoord dx, nscoord dy) +NS_IMETHODIMP +TextFrame::FindTextRuns(nsCSSLineLayout& aLineLayout) { - Text* txt = (Text*) mContent; - const PRUnichar* cp = txt->mText + mContentOffset; - const PRUnichar* end = cp + mContentLength; - - // Get a word buffer that's big enough to hold all of the text in - // case all of the text happens to be a word (not possible given how - // the justification workds, but it's the fastest check that gets us - // a big enough buffer). We only do this if we aren't going to use - // multibyte rendering. - char buf[100]; - char* s0 = buf; - if ((mFlags & TEXT_HAS_MULTIBYTE) == 0) { - PRInt32 maxLen = end - cp; - if (maxLen > sizeof(buf)) { - s0 = new char[maxLen]; - } + if (nsnull == mPrevInFlow) { + aLineLayout.AddText(this); } - - // XXX justified text doesn't render underlines (etc) over spaces - // while regular text does...fix this? - PRUint32* wp = mWords; - PRInt32 total = mContentLength; - nscoord x = dx; -#ifdef DEBUG_JUSTIFY - PRIntn numWords = mNumWords; -#endif - while (total != 0) { -#ifdef DEBUG_JUSTIFY - NS_ASSERTION(numWords > 0, "bad word data"); -#endif - PRUint32 wordInfo = *wp++; - nscoord wordWidth = GET_WORD_WIDTH(wordInfo); - PRIntn wordLen = GET_WORD_LENGTH(wordInfo); - if (wordInfo & WORD_IS_WORD) { - if (mFlags & TEXT_HAS_MULTIBYTE) { - aRenderingContext.DrawString(cp, wordLen, x, dy, mRect.width); - cp += wordLen; - } else { - char* s = s0; - char* es = s + wordLen; - while (s < es) { - PRUint8 ch = (PRUint8) *cp++; - *s++ = ch; - } - aRenderingContext.DrawString(s0, s - s0, x, dy, mRect.width); - } - } else { - // skip over space characters in text array - cp += wordLen; - } - x += wordWidth; - total -= wordLen; -#ifdef DEBUG_JUSTIFY - --numWords; - NS_ASSERTION(total >= 0, "bad word data"); -#endif - } - - if (s0 != buf) { - delete[] s0; - } -} - -NS_METHOD TextFrame::GetReflowMetrics(nsIPresContext* aCX, - nsReflowMetrics& aMetrics) -{ - // Get cached state for containing block frame - nsLineLayout* lineLayoutState = nsnull; - nsBlockReflowState* state = nsBlockFrame::FindBlockReflowState(aCX, this); - if (nsnull != state) { - lineLayoutState = state->mCurrentLine; - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_AWARE; - } - - if (0 == (mFlags & TEXT_IS_PRE)) { - if (mRect.width != 0) { - lineLayoutState->SetSkipLeadingWhiteSpace( - (0 != (mFlags & TEXT_ENDS_IN_WHITESPACE))); - } - } - } - - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - - const nsStyleFont* font = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - nsIFontMetrics* fm = aCX->GetMetricsFor(font->mFont); - aMetrics.ascent = fm->GetMaxAscent(); - aMetrics.descent = fm->GetMaxDescent(); - NS_RELEASE(fm); - return NS_OK; } -NS_METHOD TextFrame::Reflow(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsReflowState& aReflowState, - nsReflowStatus& aStatus) +NS_IMETHODIMP +TextFrame::InlineReflow(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState) { - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter TextFrame::Reflow: aMaxSize=%d,%d", aReflowState.maxSize.width, aReflowState.maxSize.height)); - // Wipe out old justification information since it's going to change - if (nsnull != mWords) { - delete[] mWords; - mWords = nsnull; - } -#ifdef DEBUG_JUSTIFY - mNumWords = 0; -#endif - // Get starting offset into the content PRInt32 startingOffset = 0; if (nsnull != mPrevInFlow) { @@ -785,16 +678,6 @@ NS_METHOD TextFrame::Reflow(nsIPresContext* aCX, startingOffset = prev->mContentOffset + prev->mContentLength; } - // Get cached state for containing block frame - nsLineLayout* lineLayoutState = nsnull; - nsBlockReflowState* state = nsBlockFrame::FindBlockReflowState(aCX, this); - if (nsnull != state) { - lineLayoutState = state->mCurrentLine; - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_AWARE; - } - } - const nsStyleFont* font = (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); @@ -811,38 +694,34 @@ NS_METHOD TextFrame::Reflow(nsIPresContext* aCX, const nsStyleText* text = (const nsStyleText*)mStyleContext->GetStyleData(eStyleStruct_Text); + nsInlineReflowStatus rs; if (NS_STYLE_WHITESPACE_PRE == text->mWhiteSpace) { // Use a specialized routine for pre-formatted text - aStatus = ReflowPre(aCX, aDesiredSize, aReflowState.maxSize, - aDesiredSize.maxElementSize, *font, startingOffset, - lineLayoutState); + rs = ReflowPre(aLineLayout, aMetrics, aReflowState, + *font, startingOffset); } else { // Use normal wrapping routine for non-pre text (this includes // text that is not wrapping) - aStatus = ReflowNormal(aCX, aDesiredSize, aReflowState.maxSize, - aDesiredSize.maxElementSize, *font, *text, - startingOffset, lineLayoutState); + rs = ReflowNormal(aLineLayout, aMetrics, aReflowState, + *font, *text, startingOffset); } - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("exit TextFrame::Reflow: %scomplete width=%d", - (NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not "), - aDesiredSize.width)); - return NS_OK; + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, + ("exit TextFrame::Reflow: rv=%x width=%d", + rs, aMetrics.width)); + return rs; } // Reflow normal text (stuff that doesn't have to deal with horizontal // tabs). Normal text reflow may or may not wrap depending on the // "whiteSpace" style property. -nsReflowStatus -TextFrame::ReflowNormal(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsSize& aMaxSize, - nsSize* aMaxElementSize, +nsInlineReflowStatus +TextFrame::ReflowNormal(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState, const nsStyleFont& aFont, const nsStyleText& aTextStyle, - PRInt32 aStartingOffset, - nsLineLayout* aLineState) + PRInt32 aStartingOffset) { Text* txt = (Text*) mContent; const PRUnichar* cp = txt->mText + aStartingOffset; @@ -850,7 +729,7 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, const PRUnichar* cpStart = cp; mContentOffset = aStartingOffset; - nsIFontMetrics* fm = aCX->GetMetricsFor(aFont.mFont); + nsIFontMetrics* fm = aLineLayout.mPresContext->GetMetricsFor(aFont.mFont); PRInt32 spaceWidth = fm->GetWidth(' '); PRBool wrapping = PR_TRUE; if (NS_STYLE_WHITESPACE_NORMAL != aTextStyle.mWhiteSpace) { @@ -859,11 +738,9 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, // Set whitespace skip flag PRBool skipWhitespace = PR_FALSE; - if (nsnull != aLineState) { - if (aLineState->mState.mSkipLeadingWhiteSpace) { - skipWhitespace = PR_TRUE; - mFlags |= TEXT_SKIP_LEADING_WS; - } + if (aLineLayout.GetSkipLeadingWhiteSpace()) { + skipWhitespace = PR_TRUE; + mFlags |= TEXT_SKIP_LEADING_WS; } // Try to fit as much of the text as possible. Note that if we are @@ -876,7 +753,7 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, // XXX XP_IS_SPACE must not return true for the unicode   character // XXX what about &zwj and it's cousins? nscoord x = 0; - nscoord maxWidth = aMaxSize.width; + nscoord maxWidth = aReflowState.maxSize.width; nscoord maxWordWidth = 0; const PRUnichar* lastWordEnd = cpStart; const PRUnichar* lastWordStart = cpStart; @@ -898,7 +775,9 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, break; } if (skipWhitespace) { - aLineState->AtSpace(); +#if XXX_fix_me + aLineLayout->AtSpace(); +#endif skipWhitespace = PR_FALSE; continue; } @@ -936,14 +815,16 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, break; } +#if XXX_fix_me // Update break state in line reflow state // XXX move this out of the loop! if (isWhitespace) { - aLineState->AtSpace(); + aLineLayout.AtSpace(); } else { - aLineState->AtWordStart(this, x); + aLineLayout.AtWordStart(this, x); } +#endif // The word fits. Add it to the run of text. x += width; @@ -961,15 +842,13 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, mFlags |= TEXT_ENDS_IN_WHITESPACE; } - if (nsnull != aLineState) { - if (0 == x) { - // Since we collapsed into nothingness (all our whitespace - // is ignored) leave the aState->mSkipLeadingWhiteSpace - // flag alone since it doesn't want leading whitespace - } - else { - aLineState->mState.mSkipLeadingWhiteSpace = endsInWhitespace; - } + if (0 == x) { + // Since we collapsed into nothingness (all our whitespace + // is ignored) leave the aState->mSkipLeadingWhiteSpace + // flag alone since it doesn't want leading whitespace + } + else { + aLineLayout.SetSkipLeadingWhiteSpace(endsInWhitespace); } // XXX too much code here: some of it isn't needed @@ -978,68 +857,64 @@ TextFrame::ReflowNormal(nsIPresContext* aCX, if (0 == mContentLength) { if (cp == end) { // The entire chunk of text was whitespace that we skipped over. - aDesiredSize.width = 0; - aDesiredSize.height = 0; - aDesiredSize.ascent = 0; - aDesiredSize.descent = 0; + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; mContentLength = end - cpStart; - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = 0; - aMaxElementSize->height = 0; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = 0; + aMetrics.maxElementSize->height = 0; } NS_RELEASE(fm); - return NS_FRAME_COMPLETE; + return NS_INLINE_REFLOW_COMPLETE; } } // Set desired size to the computed size - aDesiredSize.width = x; - aDesiredSize.height = fm->GetHeight(); - aDesiredSize.ascent = fm->GetMaxAscent(); - aDesiredSize.descent = fm->GetMaxDescent(); + aMetrics.width = x; + aMetrics.height = fm->GetHeight(); + aMetrics.ascent = fm->GetMaxAscent(); + aMetrics.descent = fm->GetMaxDescent(); if (!wrapping) { maxWordWidth = x; } - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = maxWordWidth; - aMaxElementSize->height = fm->GetHeight(); + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = maxWordWidth; + aMetrics.maxElementSize->height = fm->GetHeight(); } NS_RELEASE(fm); - return (cp == end) ? NS_FRAME_COMPLETE : NS_FRAME_NOT_COMPLETE; + return (cp == end) ? NS_INLINE_REFLOW_COMPLETE : NS_INLINE_REFLOW_NOT_COMPLETE; } -nsReflowStatus -TextFrame::ReflowPre(nsIPresContext* aCX, - nsReflowMetrics& aDesiredSize, - const nsSize& aMaxSize, - nsSize* aMaxElementSize, +nsInlineReflowStatus +TextFrame::ReflowPre(nsCSSLineLayout& aLineLayout, + nsReflowMetrics& aMetrics, + const nsReflowState& aReflowState, const nsStyleFont& aFont, - PRInt32 aStartingOffset, - nsLineLayout* aLineState) + PRInt32 aStartingOffset) { + nsInlineReflowStatus rs = NS_INLINE_REFLOW_COMPLETE; + Text* txt = (Text*) mContent; const PRUnichar* cp = txt->mText + aStartingOffset; const PRUnichar* cpStart = cp; const PRUnichar* end = cp + txt->mLength - aStartingOffset; mFlags |= TEXT_IS_PRE; - nsIFontMetrics* fm = aCX->GetMetricsFor(aFont.mFont); + nsIFontMetrics* fm = aLineLayout.mPresContext->GetMetricsFor(aFont.mFont); const PRInt32* widths = fm->GetWidths(); PRInt32 width = 0; PRBool hasMultibyte = PR_FALSE; PRUint16 tabs = 0; - PRIntn col = 0; - if (nsnull != aLineState) { - col = aLineState->GetColumn(); - } - mColumn = (PRUint16) col; + PRUint16 col = aLineLayout.GetColumn(); + mColumn = col; nscoord spaceWidth = widths[' ']; + while (cp < end) { PRUnichar ch = *cp++; if (ch == '\n') { - if (nsnull != aLineState) { - aLineState->mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_BREAK_AFTER; - } + rs = NS_INLINE_REFLOW_LINE_BREAK_AFTER; break; } if (ch == '\t') { @@ -1063,9 +938,7 @@ TextFrame::ReflowPre(nsIPresContext* aCX, } col++; } - if (nsnull != aLineState) { - aLineState->SetColumn(col); - } + aLineLayout.SetColumn(col); if (hasMultibyte) { mFlags |= TEXT_HAS_MULTIBYTE; } @@ -1073,208 +946,19 @@ TextFrame::ReflowPre(nsIPresContext* aCX, mContentOffset = aStartingOffset; mContentLength = cp - cpStart; - aDesiredSize.width = width; - aDesiredSize.height = fm->GetHeight(); - aDesiredSize.ascent = fm->GetMaxAscent(); - aDesiredSize.descent = fm->GetMaxDescent(); - if (nsnull != aMaxElementSize) { - aMaxElementSize->width = aDesiredSize.width; - aMaxElementSize->height = aDesiredSize.height; + aMetrics.width = width; + aMetrics.height = fm->GetHeight(); + aMetrics.ascent = fm->GetMaxAscent(); + aMetrics.descent = fm->GetMaxDescent(); + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = aMetrics.width; + aMetrics.maxElementSize->height = aMetrics.height; } NS_RELEASE(fm); - return (cp == end) ? NS_FRAME_COMPLETE : NS_FRAME_NOT_COMPLETE; + + return rs; } -#define NUM_WORDS 20 - -NS_METHOD TextFrame::JustifyReflow(nsIPresContext* aCX, nscoord aAvailableSpace) -{ - if (mFlags & TEXT_IS_PRE) { - // no way - return NS_OK; - } - - const nsStyleFont* font = - (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); - nsIFontMetrics* fm = aCX->GetMetricsFor(font->mFont); - PRInt32 spaceWidth = fm->GetWidth(' '); - - PRUint32 words[NUM_WORDS]; - PRUint32* wp0 = words; - PRIntn maxWords = NUM_WORDS; - - PRBool skipWhitespace = PRBool((mFlags & TEXT_SKIP_LEADING_WS) != 0); - - // Count the number of spaces and words in the text we are going to - // justify. Also measure each word in the text and skip over leading - // space and compress down whitespace. - Text* txt = (Text*) mContent; - const PRUnichar* cp = txt->mText + mContentOffset; - const PRUnichar* end = cp + mContentLength; - PRUint32* wp = wp0; - PRUint32* wpend = wp0 + maxWords; - PRIntn spaceCount = 0; - PRIntn total = 0; - while (cp < end) { - if (wp == wpend) { - // Make space for more words - PRUint32 numWords = wp - wp0; - maxWords = maxWords * 2; - PRUint32* newwp0 = new PRUint32[maxWords]; - if (nsnull == newwp0) { - goto bail; - } - nsCRT::memcpy(newwp0, wp0, sizeof(PRUint32) * numWords); - if (wp0 != words) { - delete[] wp0; - } - wp0 = newwp0; - wp = wp0 + numWords; - wpend = wp0 + maxWords; - } - - PRUint32 wordInfo; - PRUint32 wordLen; - nscoord wordWidth; - const PRUnichar* wordStart = cp; - PRUnichar ch = *cp++; - if (XP_IS_SPACE(ch)) { - // Compress whitespace down to a single whitespace - while (cp < end) { - ch = *cp; - if (XP_IS_SPACE(ch)) { - cp++; - continue; - } - break; - } - // Use wordWidth as a flag for spaces to indicate which spaces - // we give zero space to and which we don't. - if (skipWhitespace) { - wordWidth = 0; - } else { - wordWidth = spaceWidth; - spaceCount++; - } - wordInfo = WORD_IS_SPACE; - wordLen = cp - wordStart; - } else { - while (cp < end) { - ch = *cp; - if (!XP_IS_SPACE(ch)) { - cp++; - continue; - } - break; - } - wordLen = cp - wordStart; - wordWidth = fm->GetWidth(wordStart, wordLen); - skipWhitespace = PR_FALSE; - wordInfo = WORD_IS_WORD; - } - if ((wordWidth > MAX_WORD_WIDTH) || (wordLen > MAX_WORD_LENGTH)) { - // We can't fit the information about this word into our - // bitfield. Bail. - goto bail; - } - wordInfo = wordInfo | - (wordLen << WORD_LENGTH_SHIFT) | - (wordWidth << WORD_WIDTH_SHIFT); - *wp++ = wordInfo; - total += wordLen; - } - NS_ASSERTION(total == mContentLength, "bad total"); - - // Now that we know where all the words and spaces are, and we have - // measured the words, divy up the aAvailableSpace to each of the - // spaces. - if (spaceCount != 0) { - /* - * See if the last word is a space. If it is, don't count it as a space - * and give it's space to the available space. - */ - PRUint32 wordInfo = wp[-1]; - if ((wordInfo & WORD_IS_WORD) == 0) { - if (--spaceCount == 0) { - // Never mind: the one and only space was at the end. Harumph. - goto bail; - } - aAvailableSpace += spaceWidth; - // Update wordInfo to have a zero width for the trailing space - wp[-1] = WORD_IS_SPACE | (wordInfo & WORD_LENGTH_MASK); - } - nscoord add = aAvailableSpace / spaceCount; - if (add == 0) { - add = 1; - } - PRIntn numWords = wp - wp0; - mWords = new PRUint32[numWords]; - if (nsnull == mWords) { - goto bail; - } - wp = wp0; - PRUint32* tp = mWords; - PRUint32* tpend = tp + numWords; - total = 0; -#ifdef DEBUG_JUSTIFY - mNumWords = numWords; -#endif - while (--numWords >= 0) { - wordInfo = *wp++; - if (wordInfo & WORD_IS_WORD) { - // We already know about the word - *tp++ = wordInfo; - total += GET_WORD_LENGTH(wordInfo); - continue; - } else { - nscoord spaceWidth = GET_WORD_WIDTH(wordInfo); - if (spaceWidth == 0) { - // This is leading space that doesn't count - *tp++ = wordInfo; - total += GET_WORD_LENGTH(wordInfo); - continue; - } - // This is a space that gets some of the available space - if (add > aAvailableSpace) { - add = aAvailableSpace; - } - spaceWidth += add; - aAvailableSpace -= add; - if (aAvailableSpace == 0) { - // We used it all up already so stop adding - add = 0; - } - if (--spaceCount == 0) { - // Give the last space the remaining available space - spaceWidth += aAvailableSpace; - aAvailableSpace = 0; - } - if (spaceWidth > MAX_WORD_WIDTH) { - // Sad but true; leave it be. Maybe the next word can use it - *tp++ = wordInfo; - total += GET_WORD_LENGTH(wordInfo); - continue; - } - wordInfo = (wordInfo & ~WORD_WIDTH_MASK) | - (spaceWidth << WORD_WIDTH_SHIFT); - *tp++ = wordInfo; - total += GET_WORD_LENGTH(wordInfo); - } - } - NS_ASSERTION(aAvailableSpace == 0, "bad divy up"); - NS_ASSERTION(tp == tpend, "bad tp"); - NS_ASSERTION(total == mContentLength, "bad total"); - } - -bail: - if (wp0 != words) { - delete[] wp0; - } - NS_RELEASE(fm); - return NS_OK; -} -#undef NUM_WORDS - //-------------------------------------------------------------------------- // CalcActualPosition // This finds the actual interger offset into the text and the width of the @@ -1337,16 +1021,10 @@ void TextFrame::CalcCursorPosition(nsIPresContext& aCX, startingOffset = prev->GetContentOffset() + prev->GetContentLength(); } - // Get cached state for containing block frame - nsLineLayout* lineLayoutState = nsnull; - nsBlockReflowState* state = nsBlockFrame::FindBlockReflowState(&aCX, this); - if (nsnull != state) { - lineLayoutState = state->mCurrentLine; - if (nsnull != lineLayoutState) { - lineLayoutState->mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_AWARE; - } - } - +//XXX // Get cached state for containing block frame +// if (nsnull != aLineLayout) { +// aLineLayout->mReflowResult = NS_LINE_LAYOUT_REFLOW_RESULT_AWARE; +// } nsIContent * content; GetContent(content); @@ -1375,12 +1053,14 @@ void TextFrame::CalcCursorPosition(nsIPresContext& aCX, // Set whitespace skip flag PRBool skipWhitespace = PR_FALSE; - if (nsnull != lineLayoutState) { - if (lineLayoutState->SkipLeadingWhiteSpace()) { +#if XXX_wont_work + if (nsnull != aLineLayout) { + if (aLineLayout->SkipLeadingWhiteSpace()) { skipWhitespace = PR_TRUE; mFlags |= TEXT_SKIP_LEADING_WS; } } +#endif // Try to fit as much of the text as possible. Note that if we are // at the left margin then the first word always fits. In addition, @@ -1563,20 +1243,50 @@ void TextFrame::CalcCursorPosition(nsIPresContext& aCX, } +NS_IMETHODIMP +TextFrame::ListTag(FILE* out) const +{ + PRInt32 contentIndex; + GetContentIndex(contentIndex); + fprintf(out, "Text(%d)@%p", contentIndex, this); + return NS_OK; +} -NS_METHOD TextFrame::List(FILE* out, PRInt32 aIndent) const +NS_IMETHODIMP +TextFrame::List(FILE* out, PRInt32 aIndent) const { PRInt32 i; for (i = aIndent; --i >= 0; ) fputs(" ", out); - PRInt32 contentIndex; - GetContentIndex(contentIndex); - fprintf(out, "Text(%d)@%p[%d,%d] ", - contentIndex, this, - mContentOffset, mContentOffset+mContentLength-1); + + // Output the tag + ListTag(out); + nsIView* view; + GetView(view); + if (nsnull != view) { + fprintf(out, " [view=%p]", view); + NS_RELEASE(view); + } + + // Output the first/last content offset and prev/next in flow info + PRBool isComplete = + mContentOffset + mContentLength == ((Text*)mContent)->mLength; + fprintf(out, "[%d,%d,%c] ", + mContentOffset, mContentOffset+mContentLength-1, + isComplete ? 'T':'F'); + if (nsnull != mPrevInFlow) { + fprintf(out, "prev-in-flow=%p ", mPrevInFlow); + } + if (nsnull != mNextInFlow) { + fprintf(out, "next-in-flow=%p ", mNextInFlow); + } + + // Output the rect and state out << mRect; if (0 != mState) { fprintf(out, " [state=%08x]", mState); } + + // Output the text fputs("<\n", out); aIndent++; diff --git a/mozilla/layout/html/document/src/nsHTMLIFrame.cpp b/mozilla/layout/html/document/src/nsHTMLIFrame.cpp index 8ecfbea1620..cc18d5c37ef 100644 --- a/mozilla/layout/html/document/src/nsHTMLIFrame.cpp +++ b/mozilla/layout/html/document/src/nsHTMLIFrame.cpp @@ -383,6 +383,7 @@ nsHTMLIFrame::CreateFrame(nsIPresContext* aPresContext, return NS_ERROR_OUT_OF_MEMORY; } aResult = frame; + frame->SetStyleContext(aPresContext, aStyleContext); return NS_OK; } diff --git a/mozilla/layout/html/document/src/ua.css b/mozilla/layout/html/document/src/ua.css index cd905f816a1..fb0e68956f1 100644 --- a/mozilla/layout/html/document/src/ua.css +++ b/mozilla/layout/html/document/src/ua.css @@ -30,7 +30,7 @@ BODY { line-height: 1.1; background: rgb(255,255,255); color: black; - padding: 12px; + padding: 8px; display: block; cursor: arrow; } diff --git a/mozilla/layout/html/forms/src/Makefile b/mozilla/layout/html/forms/src/Makefile index bbccf9423ca..4fadc5b1acb 100644 --- a/mozilla/layout/html/forms/src/Makefile +++ b/mozilla/layout/html/forms/src/Makefile @@ -38,7 +38,8 @@ CPPSRCS = \ MODULE = raptor -INCLUDES += -I../../../base/src -I../../base/src -I../../style/src +INCLUDES += -I../../../base/src -I../../base/src -I../../style/src \ + -I../../linelayout/src REQUIRES = xpcom raptor dom netlib js diff --git a/mozilla/layout/html/forms/src/makefile.win b/mozilla/layout/html/forms/src/makefile.win index ae95a48f2e9..5ea64799354 100644 --- a/mozilla/layout/html/forms/src/makefile.win +++ b/mozilla/layout/html/forms/src/makefile.win @@ -33,10 +33,10 @@ CPP_OBJS=.\$(OBJDIR)\nsForm.obj .\$(OBJDIR)\nsInput.obj \ .\$(OBJDIR)\nsInputRadio.obj \ .\$(OBJDIR)\nsInputText.obj .\$(OBJDIR)\nsSelect.obj -LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I$(PUBLIC)\js \ - -I..\..\base\src -I..\..\style\src \ - -I..\..\..\base\src \ - -I$(PUBLIC)\dom -I$(PUBLIC)\netlib +LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I$(PUBLIC)\js \ + -I$(PUBLIC)\dom -I$(PUBLIC)\netlib \ + -I..\..\base\src -I..\..\style\src -I..\..\..\css\layout\src \ + -I..\..\..\base\src LCFLAGS = \ $(LCFLAGS) \ diff --git a/mozilla/layout/html/forms/src/nsInputFile.cpp b/mozilla/layout/html/forms/src/nsInputFile.cpp index 677bb91146d..9504fecadbd 100644 --- a/mozilla/layout/html/forms/src/nsInputFile.cpp +++ b/mozilla/layout/html/forms/src/nsInputFile.cpp @@ -21,15 +21,12 @@ #include "nsInputFile.h" #include "nsIContent.h" #include "prtypes.h" -#include "nsIFrame.h" -#include "nsISupports.h" #include "nsIAtom.h" #include "nsIPresContext.h" #include "nsIHTMLContent.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" #include "nsHTMLForms.h" -#include "nsInlineFrame.h" #include "nsIFileWidget.h" #include "nsITextWidget.h" #include "nsWidgetsCID.h" @@ -40,7 +37,7 @@ PRInt32 nsInputFileFrame::gSpacing = 40; nsString* nsInputFile::gFILE_TYPE = new nsString("file"); nsInputFileFrame::nsInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame) - : nsInlineFrame(aContent, aParentFrame) + : nsCSSInlineFrame(aContent, aParentFrame) { } @@ -106,6 +103,11 @@ void nsInputFileFrame::MouseClicked(nsIPresContext* aPresContext) NS_RELEASE(textWidget); } +// XXX this method is 100% wrong; if nsInputFileFrame really is a +// container then it's children's coordinates will be relative to the +// container, and when the container is moved the children will +// (therefore) automatically move with it. + NS_IMETHODIMP nsInputFileFrame::MoveTo(nscoord aX, nscoord aY) { @@ -125,6 +127,8 @@ nsInputFileFrame::MoveTo(nscoord aX, nscoord aY) return NS_OK; } +// XXX this shouldn't need to be done either + NS_IMETHODIMP nsInputFileFrame::SizeTo(nscoord aWidth, nscoord aHeight) { @@ -141,6 +145,9 @@ nsInputFileFrame::SizeTo(nscoord aWidth, nscoord aHeight) return NS_OK; } +// XXX hey chris: nsInlineFrame doesn't implement this anymore; this +// needs to be reworked to deal with the new inline frame code + NS_IMETHODIMP nsInputFileFrame::Reflow(nsIPresContext* aCX, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, diff --git a/mozilla/layout/html/forms/src/nsInputFile.h b/mozilla/layout/html/forms/src/nsInputFile.h index 157a8ad5f72..797dddb813b 100644 --- a/mozilla/layout/html/forms/src/nsInputFile.h +++ b/mozilla/layout/html/forms/src/nsInputFile.h @@ -20,7 +20,7 @@ #define nsInputFile_h___ #include "nsInput.h" -#include "nsInlineFrame.h" +#include "nsCSSInlineFrame.h" #include "nsInputFrame.h" class nsIAtom; @@ -28,7 +28,7 @@ class nsString; // this class definition will move to nsInputFile.cpp -class nsInputFileFrame : public nsInlineFrame { +class nsInputFileFrame : public nsCSSInlineFrame { public: nsInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame); NS_IMETHOD Reflow(nsIPresContext* aCX, diff --git a/mozilla/layout/html/style/src/nsCSSLayout.cpp b/mozilla/layout/html/style/src/nsCSSLayout.cpp index be0fcccdc1a..42755c0a074 100644 --- a/mozilla/layout/html/style/src/nsCSSLayout.cpp +++ b/mozilla/layout/html/style/src/nsCSSLayout.cpp @@ -24,7 +24,6 @@ #include "nsIPresContext.h" #include "nsRect.h" #include "nsIPtr.h" -#include "nsBlockFrame.h" #include "nsHTMLIIDs.h" NS_DEF_PTR(nsIStyleContext); @@ -309,6 +308,7 @@ GetStyleDimension(nsIPresContext* aPresContext, rv = PR_TRUE; break; } + aResult = 0; rs = rs->parentReflowState; } } @@ -338,10 +338,12 @@ nsCSSLayout::GetStyleSize(nsIPresContext* aPresContext, if (NS_OK == result) { if (GetStyleDimension(aPresContext, aReflowState, pos, pos->mWidth, aStyleSize.width)) { +NS_ASSERTION(aStyleSize.width < 100000, "bad % result"); rv |= NS_SIZE_HAS_WIDTH; } if (GetStyleDimension(aPresContext, aReflowState, pos, pos->mHeight, aStyleSize.height)) { +NS_ASSERTION(aStyleSize.height < 100000, "bad % result"); rv |= NS_SIZE_HAS_HEIGHT; } } diff --git a/mozilla/layout/html/tests/Makefile b/mozilla/layout/html/tests/Makefile index 5b424d98ae0..44be3e6fee3 100644 --- a/mozilla/layout/html/tests/Makefile +++ b/mozilla/layout/html/tests/Makefile @@ -26,8 +26,9 @@ CPPSRCS = \ TestHTMLTagLookup.cpp \ $(NULL) -INCLUDES+=-I../src -I$(PUBLIC)/xpcom -I$(PUBLIC)/raptor -I$(PUBLIC)/netlib \ - -I$(PUBLIC)\js +INCLUDES += -I../src \ + -I$(PUBLIC)/xpcom -I$(PUBLIC)/raptor -I$(PUBLIC)/netlib \ + -I$(PUBLIC)\js DIRS = diff --git a/mozilla/layout/html/tests/TestInlineFrame.cpp b/mozilla/layout/html/tests/TestInlineFrame.cpp index 087bb0b17fa..68548c481a7 100644 --- a/mozilla/layout/html/tests/TestInlineFrame.cpp +++ b/mozilla/layout/html/tests/TestInlineFrame.cpp @@ -28,7 +28,7 @@ #include "nsSplittableFrame.h" #include "nsIContentDelegate.h" #include "nsIPresContext.h" -#include "nsInlineFrame.h" +#include "nsCSSInlineFrame.h" #include "nsIAtom.h" static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID); @@ -185,7 +185,7 @@ void FixedSizeContent::ToHTML(nsString& out) /////////////////////////////////////////////////////////////////////////////// // -class InlineFrame : public nsInlineFrame +class InlineFrame : public nsCSSInlineFrame { public: InlineFrame(nsIContent* aContent, @@ -203,7 +203,7 @@ public: InlineFrame::InlineFrame(nsIContent* aContent, nsIFrame* aParent) - : nsInlineFrame(aContent, aParent) + : nsCSSInlineFrame(aContent, aParent) { } diff --git a/mozilla/layout/html/tests/makefile.win b/mozilla/layout/html/tests/makefile.win index 9b6d51a10d2..0fa03b8b215 100644 --- a/mozilla/layout/html/tests/makefile.win +++ b/mozilla/layout/html/tests/makefile.win @@ -33,12 +33,20 @@ LCFLAGS = \ $(DEFINES) \ $(NULL) -LINCS=-I$(PUBLIC)\xpcom -I$(PUBLIC)\raptor -I$(PUBLIC)\dom \ - -I$(PUBLIC)\netlib -I..\base\src -I..\style\src \ - -I..\..\base\src -I$(PUBLIC)\js +LINCS= \ + -I$(PUBLIC)\xpcom \ + -I$(PUBLIC)\raptor \ + -I$(PUBLIC)\dom \ + -I$(PUBLIC)\js \ + -I$(PUBLIC)\netlib \ + -I..\base\src \ + -I..\style\src \ + -I..\..\css\layout\src \ + -I..\..\base\src LLIBS= \ $(DIST)\lib\raptorhtmlbase_s.lib \ + $(DIST)\lib\nglcsslay_s.lib \ $(DIST)\lib\raptorhtmlstyle_s.lib \ $(DIST)\lib\raptorlayout_s.lib \ $(DIST)\lib\raptorgfx.lib \ diff --git a/mozilla/layout/makefile.win b/mozilla/layout/makefile.win index b5b1b618d1d..a13b208aea8 100644 --- a/mozilla/layout/makefile.win +++ b/mozilla/layout/makefile.win @@ -17,6 +17,6 @@ DEPTH=.. -DIRS=base html events build +DIRS=base css html events build include <$(DEPTH)\layout\config\rules.mak> diff --git a/mozilla/layout/style/ua.css b/mozilla/layout/style/ua.css index cd905f816a1..fb0e68956f1 100644 --- a/mozilla/layout/style/ua.css +++ b/mozilla/layout/style/ua.css @@ -30,7 +30,7 @@ BODY { line-height: 1.1; background: rgb(255,255,255); color: black; - padding: 12px; + padding: 8px; display: block; cursor: arrow; }