From 0a512d8393d814f3709e3e779292abd0307ad0da Mon Sep 17 00:00:00 2001 From: "kipp%netscape.com" Date: Mon, 1 Nov 1999 15:24:57 +0000 Subject: [PATCH] r=troy; reworked the way that blocks inside of inline elements are handled. It's all in the frame construction code now (bugs 15999, 16737) --- layout/base/nsCSSFrameConstructor.cpp | 995 ++++-- layout/base/nsCSSFrameConstructor.h | 43 +- layout/generic/nsBlockFrame.cpp | 620 +--- layout/generic/nsBlockFrame.h | 90 - layout/generic/nsBlockReflowState.cpp | 620 +--- layout/generic/nsBlockReflowState.h | 620 +--- layout/generic/nsInlineFrame.cpp | 2753 +++++------------ layout/generic/nsInlineFrame.h | 165 +- layout/html/base/src/nsBlockFrame.cpp | 620 +--- layout/html/base/src/nsBlockFrame.h | 90 - layout/html/base/src/nsBlockReflowState.cpp | 620 +--- layout/html/base/src/nsBlockReflowState.h | 620 +--- layout/html/base/src/nsInlineFrame.cpp | 2753 +++++------------ layout/html/base/src/nsInlineFrame.h | 165 +- .../html/style/src/nsCSSFrameConstructor.cpp | 995 ++++-- layout/html/style/src/nsCSSFrameConstructor.h | 43 +- 16 files changed, 3258 insertions(+), 8554 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 255343986cc1..016d2e772569 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -92,6 +92,12 @@ #include "nsDocument.h" #include "nsToolbarItemFrame.h" +#ifdef DEBUG +static PRBool gNoisyContentUpdates = PR_FALSE; +static PRBool gReallyNoisyContentUpdates = PR_FALSE; +static PRBool gNoisyInlineConstruction = PR_FALSE; +#endif + nsresult NS_NewThumbFrame ( nsIFrame** aNewFrame ); @@ -1844,8 +1850,7 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresContext* aPresContext, const nsStyleDisplay* childDisplay = (const nsStyleDisplay*) childStyleContext->GetStyleData(eStyleStruct_Display); if (IsTableRelated(childDisplay->mDisplay)) { - rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, aChildItems); } else { nsCOMPtr tag; aChildContent->GetTag(*getter_AddRefs(tag)); @@ -1864,12 +1869,10 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresContext* aPresContext, if (parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE) { nsIFrame* outerFrame; aParentFrame->GetParent(&outerFrame); - rv = ConstructFrame(aPresContext, aState, aChildContent, outerFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, outerFrame, aChildItems); // XXX: Seems like this is going into the inner frame's child list instead of the outer frame. - DWH } else { - rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, aChildItems); } // wrap it in a table cell, row, row group, table if it is a valid tag or display // and not whitespace. For example we don't allow map, head, body, etc. @@ -2072,7 +2075,7 @@ nsCSSFrameConstructor::ConstructDocElementTableFrame(nsIPresContext* aPresContex nsFrameConstructorState state(aPresContext, nsnull, nsnull, nsnull); nsFrameItems frameItems; - ConstructFrame(aPresContext, state, aDocElement, aParentFrame, PR_FALSE, frameItems); + ConstructFrame(aPresContext, state, aDocElement, aParentFrame, frameItems); aNewTableFrame = frameItems.childList; return NS_OK; } @@ -3602,7 +3605,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresContext* aPresConte content->SetDocument(aDocument, PR_TRUE); // create the frame and attach it to our frame - ConstructFrame(aPresContext, aState, content, aNewFrame, PR_FALSE, aChildItems); + ConstructFrame(aPresContext, aState, content, aNewFrame, aChildItems); } return NS_OK; @@ -3726,7 +3729,7 @@ nsCSSFrameConstructor::CreateAnonymousTreeCellFrames(nsIPresContext* aPresConte content->SetDocument(doc, PR_TRUE); // create the frame and attach it to our frame - ConstructFrame(aPresContext, aState, content, aNewFrame, PR_FALSE, aChildItems); + ConstructFrame(aPresContext, aState, content, aNewFrame, aChildItems); } if (count > 0) { @@ -4423,7 +4426,6 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems) { @@ -4433,6 +4435,8 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre PRBool isFloating = PR_FALSE; PRBool isBlock = aDisplay->IsBlockLevel(); nsIFrame* newFrame = nsnull; // the frame we construct + nsIFrame* newBlock = nsnull; + nsIFrame* nextInline = nsnull; nsTableCreator tableCreator; // Used to make table frames. PRBool addToHashTable = PR_TRUE; nsresult rv = NS_OK; @@ -4699,7 +4703,8 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre if (NS_SUCCEEDED(rv)) { // That worked so construct the inline and its children rv = ConstructInline(aPresContext, aState, aDisplay, aContent, - aParentFrame, aStyleContext, newFrame); + aParentFrame, aStyleContext, newFrame, + &newBlock, &nextInline); } // To keep the hash table small don't add inline frames (they're @@ -4814,6 +4819,12 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre } else if (nsnull != newFrame) { // Add the frame we just created to the flowed list aFrameItems.AddChild(newFrame); + if (newBlock) { + aFrameItems.AddChild(newBlock); + if (nextInline) { + aFrameItems.AddChild(nextInline); + } + } } if (newFrame && addToHashTable) { @@ -4827,78 +4838,6 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre return rv; } -nsresult -nsCSSFrameConstructor::ConstructBlock(nsIPresContext* aPresContext, - nsFrameConstructorState& aState, - const nsStyleDisplay* aDisplay, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame) -{ - // Initialize the frame - aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, - nsnull); - - // See if we need to create a view, e.g. the frame is absolutely positioned - nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, - aStyleContext, PR_FALSE); - - // See if the block has first-letter style applied to it... - PRBool haveFirstLetterStyle, haveFirstLineStyle; - HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, - &haveFirstLetterStyle, &haveFirstLineStyle); - - // Process the child content - nsFrameItems childItems; - nsFrameConstructorSaveState floaterSaveState; - aState.PushFloaterContainingBlock(aNewFrame, floaterSaveState, - haveFirstLetterStyle, - haveFirstLineStyle); - nsresult rv = ProcessChildren(aPresContext, aState, aContent, aNewFrame, - PR_TRUE, childItems, PR_TRUE); - - // Set the frame's initial child list - aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); - - // Set the frame's floater list if there were any floated children - if (aState.mFloatedItems.childList) { - aNewFrame->SetInitialChildList(*aPresContext, - nsLayoutAtoms::floaterList, - aState.mFloatedItems.childList); - } - - return rv; -} - -nsresult -nsCSSFrameConstructor::ConstructInline(nsIPresContext* aPresContext, - nsFrameConstructorState& aState, - const nsStyleDisplay* aDisplay, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame) -{ - // Initialize the frame - aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, - nsnull); - - // See if we need to create a view, e.g. the frame is absolutely positioned - nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, - aStyleContext, PR_FALSE); - - // Process the child content - nsFrameItems childItems; - nsresult rv = ProcessChildren(aPresContext, aState, aContent, - aNewFrame, PR_TRUE, childItems, PR_FALSE); - - // Set the frame's initial child list - aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); - - return rv; -} - nsresult nsCSSFrameConstructor::GetAdjustedParentFrame(nsIFrame* aCurrentParentFrame, PRUint8 aChildDisplayType, @@ -5201,7 +5140,6 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems) { @@ -5261,8 +5199,7 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresContext* aPresContext, // When there is no explicit frame to create, assume it's a // container and let display style dictate the rest rv = ConstructFrameByDisplayType(aPresContext, aState, display, aContent, - aParentFrame, styleContext, - aHaveFirstLetterStyle, aFrameItems); + aParentFrame, styleContext, aFrameItems); } } } @@ -5564,96 +5501,21 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, nsnull, aFrameList); } -// See if aContent is the "logical" first child of -// aContainingBlock. The check works recursively, skipping upward -// through content until we reach aContainingBlock. -static PRBool -ContentIsLogicalFirstChild(nsIContent* aContent, nsIContent* aContainingBlock) -{ - if (aContent) { - nsCOMPtr contentParent; - aContent->GetParent(*getter_AddRefs(contentParent)); - if (contentParent) { - PRInt32 ix; - contentParent->IndexOf(aContent, ix); - if (0 != ix) { - return PR_FALSE; - } - if (contentParent.get() != aContainingBlock) { - return ContentIsLogicalFirstChild(contentParent, aContainingBlock); - } - return PR_TRUE; - } - } - return PR_FALSE; -} - -nsresult -nsCSSFrameConstructor::MaybeCreateContainerFrame(nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - nsresult rv = NS_OK; -#if 0 - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - - // See if aContainer's parent has a frame... - nsCOMPtr containerParent; - aContainer->GetParent(*getter_AddRefs(containerParent)); - if (containerParent) { - nsIFrame* parentFrame = GetFrameFor(shell, aPresContext, containerParent); - if (parentFrame) { - // aContainer's parent has a frame. Maybe aContainer needs a - // frame now? If it's display none, then it doesn't. - nsCOMPtr parentStyleContext; - parentFrame->GetStyleContext(getter_AddRefs(parentStyleContext)); - nsCOMPtr styleContext; - aPresContext->ResolveStyleContextFor(aContainer, parentStyleContext, - PR_FALSE, - getter_AddRefs(styleContext)); - const nsStyleDisplay* display = (const nsStyleDisplay*) - styleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_NONE != display->mDisplay) { - // aContainer's display is not none and it has a parent - // frame. Now we see if it needs a frame after new content - // was appended. - if (IsHTMLParagraph(aContainer)) { - if (!IsEmptyContainer(aContainer)) { - // It's an HTML paragraph (P) and it has some - // content. Because of the previous checks we now know - // that the P used to have nothing but empty content and - // therefore had no frame created. This condition is no - // longer true so we create a frame for aContainer (and - // its children) and insert them into the tree... - PRInt32 ix; - containerParent->IndexOf(aContainer, ix); - if (ix >= 0) { -#ifdef DEBUG_kipp - printf("Recreating frame for HTML:P\n"); -#endif - ContentInserted(aPresContext, containerParent, aContainer, ix); - } - } - } - } - } - else { - // If aContainer's parent has no frame then there is no need - // in trying to create a frame for aContainer. - } - } - else { - // aContainer has no parent. Odd. - } -#endif - return rv; -} - NS_IMETHODIMP nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, nsIContent* aContainer, PRInt32 aNewIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentAppended container=%p index=%d\n", + aContainer, aNewIndexInContainer); + if (gReallyNoisyContentUpdates && aContainer) { + aContainer->List(stdout, 0); + } + } +#endif + nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); @@ -5694,6 +5556,28 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // Get the frame associated with the content nsIFrame* parentFrame = GetFrameFor(shell, aPresContext, aContainer); if (nsnull != parentFrame) { + + // If the frame we are manipulating is a special frame then do + // something different instead of just appending newly created + // frames. Note that only the first-in-flow is marked so we check + // before getting to the last-in-flow. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentAppended: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + // Get the parent frame's last-in-flow nsIFrame* nextInFlow = parentFrame; while (nsnull != nextInFlow) { @@ -5744,8 +5628,7 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, aContainer->ChildAt(i, *getter_AddRefs(childContent)); // Construct a child frame - ConstructFrame(aPresContext, state, childContent, parentFrame, - PR_FALSE, frameItems); + ConstructFrame(aPresContext, state, childContent, parentFrame, frameItems); } if (haveFirstLineStyle) { @@ -5772,6 +5655,13 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // Notify the parent frame passing it the list of new frames if (NS_SUCCEEDED(result) && firstAppendedFrame) { + // Perform special check for diddling around with the frames in + // a special inline frame. + if (WipeContainingBlock(aPresContext, state, blockContent, adjustedParentFrame, + frameItems.childList)) { + return NS_OK; + } + // Append the flowed frames to the principal child list AppendFrames(aPresContext, shell, state.mFrameManager, aContainer, adjustedParentFrame, firstAppendedFrame); @@ -5782,8 +5672,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mAbsoluteItems.childList) { state.mAbsoluteItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::absoluteList, - state.mAbsoluteItems.childList); + nsLayoutAtoms::absoluteList, + state.mAbsoluteItems.childList); } // If there are new fixed positioned child frames, then notify @@ -5792,8 +5682,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mFixedItems.childList) { state.mFixedItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::fixedList, - state.mFixedItems.childList); + nsLayoutAtoms::fixedList, + state.mFixedItems.childList); } // If there are new floating child frames, then notify @@ -5802,8 +5692,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mFloatedItems.childList) { state.mFloatedItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::floaterList, - state.mFloatedItems.childList); + nsLayoutAtoms::floaterList, + state.mFloatedItems.childList); } // Recover first-letter frames @@ -5826,12 +5716,6 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, } } - else { - // Since the parentFrame wasn't found, aContainer didn't have a - // frame created for it. Maybe now that it has a new child it - // should get a frame... - MaybeCreateContainerFrame(aPresContext, aContainer); - } return NS_OK; } @@ -5983,12 +5867,22 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted container=%p child=%p index=%d\n", + aContainer, aChild, aIndexInContainer); + if (gReallyNoisyContentUpdates) { + (aContainer ? aContainer : aChild)->List(stdout, 0); + } + } +#endif + #ifdef INCLUDE_XUL if (aContainer) { nsCOMPtr tag; aContainer->GetTag(*getter_AddRefs(tag)); if (tag && (tag.get() == nsXULAtoms::treechildren || - tag.get() == nsXULAtoms::treeitem)) { + tag.get() == nsXULAtoms::treeitem)) { // Walk up to the outermost tree row group frame and tell it that // content was added. nsCOMPtr parent; @@ -6012,14 +5906,14 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsTreeRowGroupFrame* treeRowGroup = (nsTreeRowGroupFrame*)parentFrame; if (treeRowGroup && treeRowGroup->IsLazy()) { nsIFrame* nextSibling = FindNextSibling(shell, aContainer, aIndexInContainer); - if(!nextSibling) + if(!nextSibling) treeRowGroup->OnContentAdded(*aPresContext); - else { + else { nsIFrame* frame = GetFrameFor(shell, aPresContext, aContainer); nsTreeRowGroupFrame* frameTreeRowGroup = (nsTreeRowGroupFrame*)frame; - if(frameTreeRowGroup) + if(frameTreeRowGroup) frameTreeRowGroup->OnContentInserted(*aPresContext, nextSibling); - } + } return NS_OK; } } @@ -6065,13 +5959,6 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } else { -#if 0 - nsIFrame* nextSibling; - nsIFrame* prevSibling; - nsIFrame* parentFrame; - GetSiblingAndParent(shell, aContainer, aIndexInContainer, - &nextSibling, &prevSibling, &parentFrame); -#endif // Find the frame that precedes the insertion point. nsIFrame* prevSibling = FindPreviousSibling(shell, aContainer, aIndexInContainer); nsIFrame* nextSibling = nsnull; @@ -6110,6 +5997,26 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, // Construct a new frame if (nsnull != parentFrame) { + // If the frame we are manipulating is a special frame then do + // something different instead of just inserting newly created + // frames. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + nsFrameItems frameItems; nsFrameConstructorState state(aPresContext, mFixedContainingBlock, GetAbsoluteContainingBlock(aPresContext, parentFrame), @@ -6168,8 +6075,45 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } - rv = ConstructFrame(aPresContext, state, aChild, parentFrame, PR_FALSE, - frameItems); + // If the frame we are manipulating is a special inline frame + // then do something different instead of just inserting newly + // created frames. + if (IsFrameSpecial(state.mFrameManager, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. + nsCOMPtr parentContainer; + blockContent->GetParent(*getter_AddRefs(parentContainer)); +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special inline\n"); + printf(" ==> blockContent=%p, parentContainer=%p\n", + blockContent.get(), parentContainer.get()); + } +#endif + if (parentContainer) { + PRInt32 ix; + parentContainer->IndexOf(blockContent, ix); + ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); + } + else { + // XXX uh oh. the block that needs reworking has no parent... + } + return NS_OK; + } + + rv = ConstructFrame(aPresContext, state, aChild, parentFrame, frameItems); + + // Perform special check for diddling around with the frames in + // a special inline frame. + if (WipeContainingBlock(aPresContext, state, blockContent, parentFrame, frameItems.childList)) { + return NS_OK; + } if (haveFirstLineStyle) { // It's possible that the new frame goes into a first-line @@ -6189,6 +6133,7 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsIFrame* newFrame = frameItems.childList; if (NS_SUCCEEDED(rv) && (nsnull != newFrame)) { + // Notify the parent frame if (isAppend) { rv = AppendFrames(aPresContext, shell, state.mFrameManager, @@ -6251,12 +6196,6 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } - else { - // Since the parentFrame wasn't found, aContainer didn't have a - // frame created for it. Maybe now that it has a new child it - // should get a frame... - MaybeCreateContainerFrame(aPresContext, aContainer); - } // Here we have been notified that content has been insert // so if the select now has a single item @@ -6424,6 +6363,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p index=%d\n", + aContainer, aChild, aIndexInContainer); + if (gReallyNoisyContentUpdates) { + aContainer->List(stdout, 0); + } + } +#endif + nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); nsCOMPtr frameManager; @@ -6524,28 +6473,31 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, } #endif // INCLUDE_XUL -#if 0 - // It's possible that we just made an HTML paragraph empty... - if (IsEmptyHTMLParagraph(aContainer)) { - nsCOMPtr containerParent; - aContainer->GetParent(*getter_AddRefs(containerParent)); - if (containerParent) { - PRInt32 ix; - containerParent->IndexOf(aContainer, ix); - if (ix >= 0) { - // No point in doing the fixup - needFixup = PR_FALSE; - rv = ContentRemoved(aPresContext, containerParent, aContainer, ix); - } - } - } -#endif - if (childFrame) { // Get the childFrame's parent frame nsIFrame* parentFrame; childFrame->GetParent(&parentFrame); + // If the frame we are manipulating is a special frame then do + // something different instead of just inserting newly created + // frames. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentRemoved: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + // Examine the containing-block for the removed content and see if // :first-letter style applies. nsIFrame* containingBlock = @@ -7578,7 +7530,7 @@ nsCSSFrameConstructor::CantRenderReplacedElement(nsIPresContext* aPresContext, // Note: if the old frame was out-of-flow, then so will the new frame // and we'll get a new placeholder frame rv = ConstructFrameByDisplayType(aPresContext, state, display, content, - inFlowParent, styleContext, PR_FALSE, frameItems); + inFlowParent, styleContext, frameItems); if (NS_SUCCEEDED(rv)) { nsIFrame* newFrame = frameItems.childList; @@ -8231,52 +8183,17 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresContext* aPresContext, } } - PRBool whitespaceDoesntMatter = PR_FALSE; - PRBool okToSkip = PR_FALSE; - if (aParentIsBlock) { - const nsStyleText* st; - aFrame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) st); - whitespaceDoesntMatter = !st->WhiteSpaceIsSignificant(); - okToSkip = whitespaceDoesntMatter; - } - // Iterate the child content objects and construct frames PRInt32 count; aContent->ChildCount(count); for (PRInt32 i = 0; i < count; i++) { nsCOMPtr childContent; if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { - if (aParentIsBlock) { -#if 0 - if (okToSkip && IsEmptyTextContent(childContent)) { - continue; - } -#endif -#if 0 - if (whitespaceDoesntMatter && IsEmptyHTMLParagraph(childContent)) { - continue; - } -#endif - } - // Construct a child frame - okToSkip = PR_FALSE; - rv = ConstructFrame(aPresContext, aState, childContent, aFrame, i == 0, - aFrameItems); + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); if (NS_FAILED(rv)) { return rv; } - - // If last frame was a blockish type of frame, then its ok to - // skip the next empty text content. - if (aParentIsBlock && whitespaceDoesntMatter && aFrameItems.lastChild) { - const nsStyleDisplay* sd; - aFrameItems.lastChild->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) sd); - if (sd->IsBlockLevel()) { - okToSkip = PR_TRUE; - } - } } } @@ -8291,14 +8208,13 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresContext* aPresContext, } } - if (aParentIsBlock && aState.mFirstLetterStyle) { - rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, - aFrame, aFrameItems); - } - - if (aParentIsBlock && aState.mFirstLineStyle) { - rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, - aFrameItems); + if (aParentIsBlock) { + if (aState.mFirstLetterStyle) { + rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + if (aState.mFirstLineStyle) { + rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } } return rv; @@ -9274,8 +9190,7 @@ nsCSSFrameConstructor::CreateTreeWidgetContent(nsIPresContext* aPresContext, nsFrameConstructorState state(aPresContext, mFixedContainingBlock, GetAbsoluteContainingBlock(aPresContext, aParentFrame), GetFloaterContainingBlock(aPresContext, aParentFrame)); - rv = ConstructFrame(aPresContext, state, aChild, aParentFrame, PR_FALSE, - frameItems); + rv = ConstructFrame(aPresContext, state, aChild, aParentFrame, frameItems); nsIFrame* newFrame = frameItems.childList; *aNewFrame = newFrame; @@ -9324,4 +9239,546 @@ nsCSSFrameConstructor::CreateTreeWidgetContent(nsIPresContext* aPresContext, return rv; } +//---------------------------------------------------------------------- +// Block/inline frame construction logic. We maintain a few invariants here: +// +// 1. Block frames contain block and inline frames. +// +// 2. Inline frames only contain inline frames. If an inline parent has a block +// child then the block child is migrated upward until it lands in a block +// parent (the inline frames containing block is where it will end up). + +// XXX consolidate these things +static PRBool +IsBlockFrame(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + const nsStyleDisplay* display; + aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); + if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) { + return PR_FALSE; + } + return PR_TRUE; +} + +static nsIFrame* +FindFirstBlock(nsIPresContext* aPresContext, nsIFrame* aKid, nsIFrame** aPrevKid) +{ + nsIFrame* prevKid = nsnull; + while (aKid) { + if (IsBlockFrame(aPresContext, aKid)) { + *aPrevKid = prevKid; + return aKid; + } + prevKid = aKid; + aKid->GetNextSibling(&aKid); + } + *aPrevKid = nsnull; + return nsnull; +} + +static nsIFrame* +FindLastBlock(nsIPresContext* aPresContext, nsIFrame* aKid) +{ + nsIFrame* lastBlock = nsnull; + while (aKid) { + if (IsBlockFrame(aPresContext, aKid)) { + lastBlock = aKid; + } + aKid->GetNextSibling(&aKid); + } + return lastBlock; +} + +static nsresult +MoveChildrenTo(nsIPresContext* aPresContext, + nsIStyleContext* aNewParentSC, + nsIFrame* aNewParent, + nsIFrame* aFrameList) +{ + while (aFrameList) { + aFrameList->SetParent(aNewParent); + aFrameList->GetNextSibling(&aFrameList); + } + return NS_OK; +} + +//---------------------------------------- + +nsresult +nsCSSFrameConstructor::ConstructBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + const nsStyleDisplay* aDisplay, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame* aNewFrame) +{ + // Initialize the frame + aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, + nsnull); + + // See if we need to create a view, e.g. the frame is absolutely positioned + nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, + aStyleContext, PR_FALSE); + + // See if the block has first-letter style applied to it... + PRBool haveFirstLetterStyle, haveFirstLineStyle; + HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, + &haveFirstLetterStyle, &haveFirstLineStyle); + + // Process the child content + nsFrameItems childItems; + nsFrameConstructorSaveState floaterSaveState; + aState.PushFloaterContainingBlock(aNewFrame, floaterSaveState, + haveFirstLetterStyle, + haveFirstLineStyle); + nsresult rv = ProcessBlockChildren(aPresContext, aState, aContent, aNewFrame, + PR_TRUE, childItems, PR_TRUE); + + // Set the frame's initial child list + aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); + + // Set the frame's floater list if there were any floated children + if (aState.mFloatedItems.childList) { + aNewFrame->SetInitialChildList(*aPresContext, + nsLayoutAtoms::floaterList, + aState.mFloatedItems.childList); + } + + return rv; +} + +nsresult +nsCSSFrameConstructor::ProcessBlockChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool aParentIsBlock) +{ + nsresult rv = NS_OK; + nsCOMPtr styleContext; + + if (aCanHaveGeneratedContent) { + // Probe for generated content before + nsIFrame* generatedFrame; + aFrame->GetStyleContext(getter_AddRefs(styleContext)); + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::beforePseudo, + aParentIsBlock, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + // Iterate the child content objects and construct frames + PRInt32 count; + aContent->ChildCount(count); + for (PRInt32 i = 0; i < count; i++) { + nsCOMPtr childContent; + if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { + // Construct a child frame + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); + if (NS_FAILED(rv)) { + return rv; + } + } + } + + if (aCanHaveGeneratedContent) { + // Probe for generated content after + nsIFrame* generatedFrame; + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::afterPseudo, + aParentIsBlock, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + if (aParentIsBlock) { + if (aState.mFirstLetterStyle) { + rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + if (aState.mFirstLineStyle) { + rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + } + + return rv; +} + +// When inline frames get weird and have block frames in them, we +// annotate them to help us respond to incremental content changes +// more easily. + +static void +DestroyInlineFrameAnnotation(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue) +{ +} + +PRBool +nsCSSFrameConstructor::IsFrameSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame) +{ + void* value; + nsresult rv = aFrameManager->GetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, 0, &value); + if (NS_OK == rv) { + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsCSSFrameConstructor::IsFrameSpecial(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + // Get to aFrame's first-in-flow; only the first-in-flow is marked + // with an annotation. + nsSplittableType splits; + aFrame->IsSplittable(splits); + if (splits != NS_FRAME_NOT_SPLITTABLE) { + nsIFrame* prevInFlow = aFrame; + while (prevInFlow) { + aFrame = prevInFlow; + prevInFlow->GetPrevInFlow(&prevInFlow); + } + } + + PRBool result = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + void* value; + nsresult rv = frameManager->GetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, + 0, &value); + if (NS_OK == rv) { + result = PR_TRUE; + } + } + } + return result; +} + +void +nsCSSFrameConstructor::SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame) +{ + aFrameManager->SetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, + (void*) PR_TRUE, DestroyInlineFrameAnnotation); +} + +PRBool +nsCSSFrameConstructor::AreAllKidsInline(nsIFrame* aFrameList) +{ + nsIFrame* kid = aFrameList; + while (kid) { + if (!IsInlineFrame(kid)) { + return PR_FALSE; + } + kid->GetNextSibling(&kid); + } + return PR_TRUE; +} + +nsresult +nsCSSFrameConstructor::ConstructInline(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + const nsStyleDisplay* aDisplay, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame* aNewFrame, + nsIFrame** aNewBlockFrame, + nsIFrame** aNextInlineFrame) +{ + // Initialize the frame + aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, nsnull); + + // Process the child content + nsFrameItems childItems; + PRBool kidsAllInline; + nsresult rv = ProcessInlineChildren(aPresContext, aState, aContent, + aNewFrame, PR_TRUE, childItems, &kidsAllInline); + if (kidsAllInline) { + // Set the inline frame's initial child list + aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); + *aNewBlockFrame = nsnull; + *aNextInlineFrame = nsnull; + return rv; + } + + // This inline frame contains several types of children. Therefore + // this frame has to be chopped into several pieces. We will produce + // as a result of this 3 lists of children. The first list contains + // all of the inline children that preceed the first block child + // (and may be empty). The second list contains all of the block + // children and any inlines that are between them (and must not be + // empty, otherwise - why are we here?). The final list contains all + // of the inline children that follow the final block child. + + // Find the first block child which defines list1 and list2 + nsIFrame* list1 = childItems.childList; + nsIFrame* prevToFirstBlock; + nsIFrame* list2 = FindFirstBlock(aPresContext, list1, &prevToFirstBlock); + if (prevToFirstBlock) { + prevToFirstBlock->SetNextSibling(nsnull); + } + else { + list1 = nsnull; + } + + // Find the last block child which defines the end of list2 and the + // start of list3 + nsIFrame* afterFirstBlock; + list2->GetNextSibling(&afterFirstBlock); + nsIFrame* list3 = nsnull; + nsIFrame* lastBlock = FindLastBlock(aPresContext, afterFirstBlock); + if (!lastBlock) { + lastBlock = list2; + } + lastBlock->GetNextSibling(&list3); + lastBlock->SetNextSibling(nsnull); + + // list1's frames belong to this inline frame so go ahead and take them + aNewFrame->SetInitialChildList(*aPresContext, nsnull, list1); + + // list2's frames belong to an anonymous block that we create right + // now. The anonymous block will be the parent of the block children + // of the inline. + nsIFrame* blockFrame; + NS_NewBlockFrame(&blockFrame); + nsCOMPtr blockSC; + aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::mozAnonymousBlock, + aStyleContext, PR_FALSE, + getter_AddRefs(blockSC)); + blockFrame->Init(*aPresContext, aContent, aParentFrame, blockSC, nsnull); + MoveChildrenTo(aPresContext, blockSC, blockFrame, list2); + blockFrame->SetInitialChildList(*aPresContext, nsnull, list2); + + // list3's frames belong to another inline frame + nsIFrame* inlineFrame = nsnull; + NS_NewInlineFrame(&inlineFrame); + inlineFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, nsnull); + if (list3) { + // Reparent (cheaply) the frames in list3 - we don't have to futz + // with their style context because they already have the right one. + nsFrameList list; + list.AppendFrames(inlineFrame, list3); + } + inlineFrame->SetInitialChildList(*aPresContext, nsnull, list3); + + // Mark the 3 frames as special. That way if any of the + // append/insert/remove methods try to fiddle with the children, the + // containing block will be reframed instead. + SetFrameIsSpecial(aState.mFrameManager, aNewFrame); + SetFrameIsSpecial(aState.mFrameManager, blockFrame); + SetFrameIsSpecial(aState.mFrameManager, inlineFrame); + +#ifdef DEBUG + if (gNoisyInlineConstruction) { + printf("nsCSSFrameConstructor::ConstructInline:\n"); + printf(" ==> leading inline frame:\n"); + aNewFrame->List(aPresContext, stdout, 2); + printf(" ==> block frame:\n"); + blockFrame->List(aPresContext, stdout, 2); + printf(" ==> trailing inline frame:\n"); + inlineFrame->List(aPresContext, stdout, 2); + } +#endif + + *aNewBlockFrame = blockFrame; + *aNextInlineFrame = inlineFrame; + + return rv; +} + +nsresult +nsCSSFrameConstructor::ProcessInlineChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool* aKidsAllInline) +{ + nsresult rv = NS_OK; + nsCOMPtr styleContext; + + if (aCanHaveGeneratedContent) { + // Probe for generated content before + nsIFrame* generatedFrame; + aFrame->GetStyleContext(getter_AddRefs(styleContext)); + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::beforePseudo, + PR_FALSE, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + // Iterate the child content objects and construct frames + PRBool allKidsInline = PR_TRUE; + PRInt32 count; + aContent->ChildCount(count); + for (PRInt32 i = 0; i < count; i++) { + nsCOMPtr childContent; + if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { + // Construct a child frame + nsIFrame* oldLastChild = aFrameItems.lastChild; + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); + if (NS_FAILED(rv)) { + return rv; + } + + // Examine newly added children (we may have added more than one + // child if the child was another inline frame that ends up + // being carved in 3 pieces) to maintain the allKidsInline flag. + if (allKidsInline) { + nsIFrame* kid; + if (oldLastChild) { + oldLastChild->GetNextSibling(&kid); + } + else { + kid = aFrameItems.childList; + } + while (kid) { + if (!IsInlineFrame(kid)) { + allKidsInline = PR_FALSE; + break; + } + kid->GetNextSibling(&kid); + } + } + } + } + + if (aCanHaveGeneratedContent) { + // Probe for generated content after + nsIFrame* generatedFrame; + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::afterPseudo, + PR_FALSE, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + *aKidsAllInline = allKidsInline; + + return rv; +} + +PRBool +nsCSSFrameConstructor::WipeContainingBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aBlockContent, + nsIFrame* aFrame, + nsIFrame* aFrameList) +{ + // Before we go and append the frames, check for a special + // situation: an inline frame that will now contain block + // frames. This is a no-no and the frame construction logic knows + // how to fix this. + const nsStyleDisplay* parentDisplay; + aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&) parentDisplay); + if (NS_STYLE_DISPLAY_INLINE == parentDisplay->mDisplay) { + if (!AreAllKidsInline(aFrameList)) { + // Ok, reverse tracks: wipe out the frames we just created + nsFrameList tmp(aFrameList); + tmp.DestroyFrames(*aPresContext); + if (aState.mAbsoluteItems.childList) { + tmp.SetFrames(aState.mAbsoluteItems.childList); + tmp.DestroyFrames(*aPresContext); + } + if (aState.mFixedItems.childList) { + tmp.SetFrames(aState.mFixedItems.childList); + tmp.DestroyFrames(*aPresContext); + } + if (aState.mFloatedItems.childList) { + tmp.SetFrames(aState.mFloatedItems.childList); + tmp.DestroyFrames(*aPresContext); + } + + // Tell parent of the containing block to reformulate the + // entire block. This is painful and definitely not optimal + // but it will *always* get the right answer. + nsCOMPtr parentContainer; + aBlockContent->GetParent(*getter_AddRefs(parentContainer)); +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::WipeContainingBlock: aBlockContent=%p parentContainer=%p\n", + aBlockContent, parentContainer.get()); + } +#endif + if (parentContainer) { + PRInt32 ix; + parentContainer->IndexOf(aBlockContent, ix); + ContentReplaced(aPresContext, parentContainer, aBlockContent, aBlockContent, ix); + } + else { + // XXX uh oh. the block we need to reframe has no parent! + } + return PR_TRUE; + } + } + return PR_FALSE; +} + +nsresult +nsCSSFrameConstructor::ReframeContainingBlock(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + // Get the parent of the target frame. From there we look for the + // containing block in case the target frame is already a block + // (which can happen when an inline frame wraps some of its content + // in an anonymous block; see ConstructInline) + nsIFrame* parentFrame; + aFrame->GetParent(&parentFrame); + if (!parentFrame) { + return RecreateEntireFrameTree(aPresContext); + } + + // Now find the containing block + nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, parentFrame); + if (!containingBlock) { + return RecreateEntireFrameTree(aPresContext); + } + + // And get the containingBlock's content + nsCOMPtr blockContent; + containingBlock->GetContent(getter_AddRefs(blockContent)); + if (!blockContent) { + return RecreateEntireFrameTree(aPresContext); + } + + // Now find the containingBlock's content's parent + nsCOMPtr parentContainer; + blockContent->GetParent(*getter_AddRefs(parentContainer)); + if (!parentContainer) { + return RecreateEntireFrameTree(aPresContext); + } + +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf(" ==> blockContent=%p, parentContainer=%p\n", + blockContent.get(), parentContainer.get()); + } +#endif + + PRInt32 ix; + parentContainer->IndexOf(blockContent, ix); + nsresult rv = ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); + return rv; +} + +nsresult +nsCSSFrameConstructor::RecreateEntireFrameTree(nsIPresContext* aPresContext) +{ + // XXX write me some day + return NS_OK; +} diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 143a1fd9ba9d..dd6814dca21d 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -148,7 +148,6 @@ protected: nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems); nsresult ConstructDocElementFrame(nsIPresContext* aPresContext, @@ -506,7 +505,6 @@ protected: nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems); nsresult GetAdjustedParentFrame(nsIFrame* aCurrentParentFrame, @@ -662,13 +660,49 @@ InitializeSelectFrame(nsIPresContext* aPresContext, nsIStyleContext* aStyleContext, nsIFrame* aNewFrame); + nsresult ProcessBlockChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool aParentIsBlock); + nsresult ConstructInline(nsIPresContext* aPresContext, nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay, nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame); + nsIFrame* aNewFrame, + nsIFrame** aNewBlockFrame, + nsIFrame** aNextInlineFrame); + + nsresult ProcessInlineChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool* aKidsAllInline); + + PRBool AreAllKidsInline(nsIFrame* aFrameList); + + PRBool IsFrameSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame); + + PRBool IsFrameSpecial(nsIPresContext* aPresContext, nsIFrame* aFrame); + + void SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame); + + PRBool WipeContainingBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* blockContent, + nsIFrame* aFrame, + nsIFrame* aFrameList); + + nsresult ReframeContainingBlock(nsIPresContext* aPresContext, nsIFrame* aFrame); + + nsresult RecreateEntireFrameTree(nsIPresContext* aPresContext); //---------------------------------------- @@ -757,9 +791,6 @@ InitializeSelectFrame(nsIPresContext* aPresContext, nsIFrame* aPrevSibling, nsFrameItems& aFrameItems); - nsresult MaybeCreateContainerFrame(nsIPresContext* aPresContext, - nsIContent* aContainer); - protected: nsIDocument* mDocument; diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index b9a35c5a3ce3..aabaf7359048 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -40,9 +40,6 @@ class nsFirstLineFrame; */ #define NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET 0x80000000 #define NS_BLOCK_IS_HTML_PARAGRAPH 0x40000000 -#ifdef BLOCK_DOES_FIRST_LINE -#define NS_BLOCK_HAS_FIRST_LINE_STYLE 0x20000000 -#endif #define NS_BLOCK_HAS_FIRST_LETTER_STYLE 0x10000000 #define nsBlockFrameSuper nsHTMLContainerFrame @@ -146,10 +143,6 @@ protected: nsIStyleContext* GetFirstLetterStyle(nsIPresContext* aPresContext); -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* GetFirstLineStyle(nsIPresContext* aPresContext); -#endif - void SetFlags(PRUint32 aFlags) { mFlags = aFlags; } @@ -173,22 +166,6 @@ protected: nsIFrame* aFrameList, nsIFrame* aPrevSibling); -#ifdef BLOCK_DOES_FIRST_LINE - nsresult AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling); - - nsIFrame* TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid); - - nsresult RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame); - - nsresult WrapFramesInFirstLineFrame(nsIPresContext* aPresContext); -#endif - void FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame); nsresult DoRemoveFrame(nsIPresContext* aPresContext, @@ -381,72 +358,5 @@ protected: friend class nsBlockReflowState; }; -//---------------------------------------------------------------------- - -#define nsAnonymousBlockFrameSuper nsBlockFrame - -// Anonymous block frame. An anonymous block is used by some other -// container (the parent frame) to provide block reflow for a set of -// child frames. The parent is responsible for the maintainance of the -// anonymous blocks child list. To accomplish this, the normal methods -// for managing the child list (AppendFrames, InsertFrames, and -// RemoveFrame) forward the operation to the parent frame (the -// container of the anonymous block). -class nsAnonymousBlockFrame : public nsAnonymousBlockFrameSuper { -public: - friend nsresult NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame); - - // nsIFrame overrides - - // AppendFrames/InsertFrames/RemoveFrame are implemented to forward - // the method call to the parent frame. - NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - - // These methods are used by the parent frame to actually modify the - // child frames of the anonymous block frame. - nsresult AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - - nsresult InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - - // Take the first frame away from the anonymous block frame. The - // caller is responsible for the first frames final disposition - // (e.g. deleting it if it wants to). - void RemoveFirstFrame(); - - // Remove from the blocks list of children the frames starting at - // aFrame until the end of the child list. The caller is responsible - // for the first frames final disposition (e.g. deleting it if it - // wants to). - void RemoveFramesFrom(nsIFrame* aFrame); - -protected: - nsAnonymousBlockFrame(); - ~nsAnonymousBlockFrame(); -}; - #endif /* nsBlockFrame_h___ */ diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/generic/nsBlockReflowState.h b/layout/generic/nsBlockReflowState.h index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/generic/nsBlockReflowState.h +++ b/layout/generic/nsBlockReflowState.h @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 6b1a04b6719f..9df8320eb064 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -16,13 +16,11 @@ * Corporation. Portions created by Netscape are Copyright (C) 1998 * Netscape Communications Corporation. All Rights Reserved. */ +#include "nsCOMPtr.h" #include "nsInlineFrame.h" -#include "nsBlockFrame.h" -#include "nsBlockReflowContext.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" -#include "nsCOMPtr.h" #include "nsIStyleContext.h" #include "nsIPresShell.h" #include "nsIPresContext.h" @@ -31,24 +29,804 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLayoutAtoms.h" -// XXX TODO: -// append/insert/remove floater testing - -// Theory of operation: -// XXX write this - -#ifdef DEBUG -#undef NOISY_ANON_BLOCK -#undef NOISY_REFLOW_REASON -#else -#undef NOISY_ANON_BLOCK -#undef NOISY_REFLOW_REASON -#endif +#define NOISY_FINAL_SIZE nsIID nsInlineFrame::kInlineFrameCID = NS_INLINE_FRAME_CID; ////////////////////////////////////////////////////////////////////// +// Basic nsInlineFrame methods + +nsresult +NS_NewInlineFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsInlineFrame* it = new nsInlineFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsInlineFrame::nsInlineFrame() +{ +} + +NS_IMETHODIMP +nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kInlineFrameCID)) { + nsInlineFrame* tmp = this; + *aInstancePtr = (void*) tmp; + return NS_OK; + } + return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr); +} + +NS_IMETHODIMP +nsInlineFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Inline", aResult); +} + +NS_IMETHODIMP +nsInlineFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::inlineFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aFrameList) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (aFrameList) { + mFrames.AppendFrames(this, aFrameList); + + // generate a reflow command for this frame + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (aFrameList) { + // Insert frames after aPrevFrame + mFrames.InsertFrames(this, aPrevFrame, aFrameList); + + // generate a reflow command for this frame + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + + if (aOldFrame) { + // Loop and destroy the frame and all of its continuations. + PRBool generateReflowCommand = PR_FALSE; + nsIFrame* oldFrameParent; + aOldFrame->GetParent(&oldFrameParent); + nsInlineFrame* parent = (nsInlineFrame*) oldFrameParent; + while (nsnull != aOldFrame) { + // If the frame being removed has zero size then don't bother + // generating a reflow command, otherwise make sure we do. + nsRect bbox; + aOldFrame->GetRect(bbox); + if (bbox.width || bbox.height) { + generateReflowCommand = PR_TRUE; + } + + // When the parent is an inline frame we have a simple task - just + // remove the frame from its parents list and generate a reflow + // command. + nsIFrame* oldFrameNextInFlow; + aOldFrame->GetNextInFlow(&oldFrameNextInFlow); + nsSplittableType st; + aOldFrame->IsSplittable(st); + if (NS_FRAME_NOT_SPLITTABLE != st) { + nsSplittableFrame::RemoveFromFlow(aOldFrame); + } + parent->mFrames.DestroyFrame(aPresContext, aOldFrame); + aOldFrame = oldFrameNextInFlow; + if (nsnull != aOldFrame) { + aOldFrame->GetParent((nsIFrame**) &parent); + } + } + + if (generateReflowCommand) { + // generate a reflow command for "this" + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (!aOldFrame || !aNewFrame) { + return NS_ERROR_INVALID_ARG; + } + + // Replace the old frame with the new frame in the list, then remove the old frame + mFrames.ReplaceFrame(this, aOldFrame, aNewFrame); + aOldFrame->Destroy(aPresContext); + + // generate a reflow command for "this" + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + + return NS_OK; +} + +////////////////////////////////////////////////////////////////////// +// Reflow methods + +NS_IMETHODIMP +nsInlineFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + if (nsnull == aReflowState.mLineLayout) { + return NS_ERROR_INVALID_ARG; + } + DrainOverflow(&aPresContext); + + if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { +#ifdef DEBUG_kipp + { + extern char* nsPresShell_ReflowStackPointerTop; + char marker; + char* newsp = (char*) ▮ + printf("XXX: frame tree is too deep; approx stack size = %d\n", + nsPresShell_ReflowStackPointerTop - newsp); + } +#endif + aStatus = NS_FRAME_COMPLETE; + return NS_OK; + } + + // Set our own reflow state (additional state above and beyond + // aReflowState) + InlineReflowState irs; + irs.mPrevFrame = nsnull; + irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; + irs.mNextRCFrame = nsnull; + if (eReflowReason_Incremental == aReflowState.reason) { + // Peel off the next frame in the path if this is an incremental + // reflow aimed at one of the children. + nsIFrame* target; + aReflowState.reflowCommand->GetTarget(target); + if (this != target) { + aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); + } + } + + nsresult rv; + if (mFrames.IsEmpty()) { + // Try to pull over one frame before starting so that we know + // whether we have an anonymous block or not. + PRBool complete; + (void) PullOneFrame(&aPresContext, irs, &complete); + } + + rv = ReflowFrames(&aPresContext, aReflowState, irs, aMetrics, aStatus); + + // Note: the line layout code will properly compute our + // NS_FRAME_OUTSIDE_CHILDREN state for us. + + return rv; +} + +NS_IMETHODIMP +nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) +{ + nsIFrame* frame = mFrames.FirstChild(); + while (nsnull != frame) { + frame->FindTextRuns(aLineLayout); + frame->GetNextSibling(&frame); + } + return NS_OK; +} + +void +nsInlineFrame::DrainOverflow(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); + + if (prevOverflowFrames) { + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + for (nsIFrame* f = prevOverflowFrames; f; f->GetNextSibling(&f)) { + nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevInFlow, this); + } + mFrames.InsertFrames(this, nsnull, prevOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); + if (overflowFrames) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + mFrames.AppendFrames(nsnull, overflowFrames); + } +} + +nsresult +nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& irs, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) +{ + nsresult rv = NS_OK; + aStatus = NS_FRAME_COMPLETE; + + nsLineLayout* lineLayout = aReflowState.mLineLayout; + nscoord leftEdge = 0; + if (nsnull == mPrevInFlow) { + leftEdge = aReflowState.mComputedBorderPadding.left; + } + nscoord availableWidth = aReflowState.availableWidth; + if (NS_UNCONSTRAINEDSIZE != availableWidth) { + // Subtract off left and right border+padding from availableWidth + availableWidth -= leftEdge; + availableWidth -= aReflowState.mComputedBorderPadding.right; + } + lineLayout->BeginSpan(this, &aReflowState, leftEdge, leftEdge + availableWidth); + + // First reflow our current children + nsIFrame* frame = mFrames.FirstChild(); + PRBool done = PR_FALSE; + while (nsnull != frame) { + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); + if (NS_FAILED(rv)) { + done = PR_TRUE; + break; + } + if (NS_FRAME_COMPLETE != aStatus) { + if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { + done = PR_TRUE; + break; + } + } + irs.mPrevFrame = frame; + frame->GetNextSibling(&frame); + } + + // Attempt to pull frames from our next-in-flow until we can't + if (!done && (nsnull != mNextInFlow)) { + while (!done) { + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + PRBool isComplete; + frame = PullOneFrame(aPresContext, irs, &isComplete); + if (nsnull == frame) { + if (!isComplete) { + aStatus = NS_FRAME_NOT_COMPLETE; + } + break; + } + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); + if (NS_FAILED(rv)) { + done = PR_TRUE; + break; + } + if (NS_FRAME_COMPLETE != aStatus) { + if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { + done = PR_TRUE; + break; + } + } + irs.mPrevFrame = frame; + } + } +#ifdef DEBUG + if (NS_FRAME_COMPLETE == aStatus) { + // We can't be complete AND have overflow frames! + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE); + NS_ASSERTION(!overflowFrames, "whoops"); + } +#endif + + // If after reflowing our children they take up no area then make + // sure that we don't either. + // + // Note: CSS demands that empty inline elements still affect the + // line-height calculations. However, continuations of an inline + // that are empty we force to empty so that things like collapsed + // whitespace in an inline element don't affect the line-height. + nsSize size; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + if ((0 == size.height) && (0 == size.width) && + ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { + // This is a continuation of a previous inline. Therefore make + // sure we don't affect the line-height. + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = 0; + aMetrics.maxElementSize->height = 0; + } + } + else { + // Compute final width + aMetrics.width = size.width; + if (nsnull == mPrevInFlow) { + aMetrics.width += aReflowState.mComputedBorderPadding.left; + } + if (NS_FRAME_IS_COMPLETE(aStatus)) { + aMetrics.width += aReflowState.mComputedBorderPadding.right; + } + + const nsStyleFont* font; + GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); + aReflowState.rendContext->SetFont(font->mFont); + nsCOMPtr fm; + aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); + + // Compute final height of the frame. + // + // Do things the standard css2 way -- though it's hard to find it + // in the css2 spec! It's actually found in the css1 spec section + // 4.4 (you will have to read between the lines to really see + // it). + // + // The height of our box is the sum of our font size plus the top + // and bottom border and padding. The height of children do not + // affect our height. + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; + + // Note: we normally use the actual font height for computing the + // line-height raw value from the style context. On systems where + // they disagree the actual font height is more appropriate. This + // little hack lets us override that behavior to allow for more + // precise layout in the face of imprecise fonts. + if (nsHTMLReflowState::UseComputedHeight()) { + aMetrics.height = font->mFont.size + + aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; + } + } + + // For now our combined area is zero. The real value will be + // computed during vertical alignment of the line we are on. + aMetrics.mCombinedArea.x = 0; + aMetrics.mCombinedArea.y = 0; + aMetrics.mCombinedArea.width = aMetrics.width; + aMetrics.mCombinedArea.height = aMetrics.height; + +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": metrics=%d,%d ascent=%d descent=%d\n", + aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); +#endif + + return rv; +} + +nsresult +nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& irs, + nsIFrame* aFrame, + nsReflowStatus& aStatus) +{ + nsLineLayout* lineLayout = aReflowState.mLineLayout; + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); + if (NS_FAILED(rv)) { + return rv; + } + if (NS_INLINE_IS_BREAK(aStatus)) { + if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { + if (aFrame != mFrames.FirstChild()) { + // Change break-before status into break-after since we have + // already placed at least one child frame. This preserves the + // break-type so that it can be propogated upward. + aStatus = NS_FRAME_NOT_COMPLETE | + NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | + (aStatus & NS_INLINE_BREAK_TYPE_MASK); + PushFrames(aPresContext, aFrame, irs.mPrevFrame); + } + else { + // Preserve reflow status when breaking-before our first child + // and propogate it upward without modification. + } + } + else { + // Break-after + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + nsIFrame* newFrame; + rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); + if (NS_FAILED(rv)) { + return rv; + } + } + nsIFrame* nextFrame; + aFrame->GetNextSibling(&nextFrame); + if (nsnull != nextFrame) { + aStatus |= NS_FRAME_NOT_COMPLETE; + PushFrames(aPresContext, nextFrame, aFrame); + } + else if (nsnull != mNextInFlow) { + // We must return an incomplete status if there are more child + // frames remaining in a next-in-flow that follows this frame. + nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; + while (nsnull != nextInFlow) { + if (nextInFlow->mFrames.NotEmpty()) { + aStatus |= NS_FRAME_NOT_COMPLETE; + break; + } + nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; + } + } + } + } + else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + nsIFrame* newFrame; + rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); + if (NS_FAILED(rv)) { + return rv; + } + if (!reflowingFirstLetter) { + nsIFrame* nextFrame; + aFrame->GetNextSibling(&nextFrame); + if (nsnull != nextFrame) { + PushFrames(aPresContext, nextFrame, aFrame); + } + } + } + return rv; +} + +nsIFrame* +nsInlineFrame::PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& irs, + PRBool* aIsComplete) +{ + PRBool isComplete = PR_TRUE; + + nsIFrame* frame = nsnull; + nsInlineFrame* nextInFlow = irs.mNextInFlow; + while (nsnull != nextInFlow) { + frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); + if (nsnull != frame) { + isComplete = PR_FALSE; + nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); + break; + } + nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; + irs.mNextInFlow = nextInFlow; + } + + *aIsComplete = isComplete; + return frame; +} + +void +nsInlineFrame::PushFrames(nsIPresContext* aPresContext, + nsIFrame* aFromChild, + nsIFrame* aPrevSibling) +{ + NS_PRECONDITION(nsnull != aFromChild, "null pointer"); + NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); +#ifdef DEBUG + nsIFrame* prevNextSibling; + aPrevSibling->GetNextSibling(&prevNextSibling); + NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); +#endif + + // Disconnect aFromChild from its previous sibling + aPrevSibling->SetNextSibling(nsnull); + + // Add the frames to our overflow list (let our next in flow drain + // our overflow list when it is ready) + SetOverflowFrames(aPresContext, aFromChild); +} + +////////////////////////////////////////////////////////////////////// + +PRIntn +nsInlineFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow; + if (prev->mRect.height || prev->mRect.width) { + // Prev-in-flow is not empty therefore we don't render our left + // border edge. + skip |= 1 << NS_SIDE_LEFT; + } + else { + // If the prev-in-flow is empty, then go ahead and let our right + // edge border render. + } + } + if (nsnull != mNextInFlow) { + nsInlineFrame* next = (nsInlineFrame*) mNextInFlow; + if (next->mRect.height || next->mRect.width) { + // Next-in-flow is not empty therefore we don't render our right + // border edge. + skip |= 1 << NS_SIDE_RIGHT; + } + else { + // If the next-in-flow is empty, then go ahead and let our right + // edge border render. + } + } + return skip; +} + +////////////////////////////////////////////////////////////////////// + +// nsLineFrame implementation + +static void +ReParentChildListStyle(nsIPresContext* aPresContext, + nsIStyleContext* aParentStyleContext, + nsFrameList& aFrameList) +{ + nsIFrame* kid = aFrameList.FirstChild(); + while (nsnull != kid) { + aPresContext->ReParentStyleContext(kid, aParentStyleContext); + kid->GetNextSibling(&kid); + } +} + +nsresult +NS_NewFirstLineFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsInlineFrame* it = new nsFirstLineFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsFirstLineFrame::nsFirstLineFrame() +{ +} + +NS_IMETHODIMP +nsFirstLineFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Line", aResult); +} + +NS_IMETHODIMP +nsFirstLineFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::lineFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +void +nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame) +{ + nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame); + if (prevFrame) { + prevFrame->SetNextSibling(nsnull); + } + else { + mFrames.SetFrames(nsnull); + } +} + +nsIFrame* +nsFirstLineFrame::PullOneFrame(nsIPresContext* aPresContext, InlineReflowState& irs, PRBool* aIsComplete) +{ + nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete); + if (frame && !mPrevInFlow) { + // We are a first-line frame. Fixup the child frames + // style-context that we just pulled. + aPresContext->ReParentStyleContext(frame, mStyleContext); + } + return frame; +} + +void +nsFirstLineFrame::DrainOverflow(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); + if (prevOverflowFrames) { + nsFrameList frames(prevOverflowFrames); + + ReParentChildListStyle(aPresContext, mStyleContext, frames); + mFrames.InsertFrames(this, nsnull, prevOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); + if (overflowFrames) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + nsFrameList frames(overflowFrames); + + ReParentChildListStyle(aPresContext, mStyleContext, frames); + mFrames.AppendFrames(nsnull, overflowFrames); + } +} + +NS_IMETHODIMP +nsFirstLineFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + if (nsnull == aReflowState.mLineLayout) { + return NS_ERROR_INVALID_ARG; + } + DrainOverflow(&aPresContext); + + // Set our own reflow state (additional state above and beyond + // aReflowState) + InlineReflowState irs; + irs.mPrevFrame = nsnull; + irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; + irs.mNextRCFrame = nsnull; + if (eReflowReason_Incremental == aReflowState.reason) { + // Peel off the next frame in the path if this is an incremental + // reflow aimed at one of the children. + nsIFrame* target; + aReflowState.reflowCommand->GetTarget(target); + if (this != target) { + aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); + } + } + + nsresult rv; + PRBool wasEmpty = mFrames.IsEmpty(); + if (wasEmpty) { + // Try to pull over one frame before starting so that we know + // whether we have an anonymous block or not. + PRBool complete; + PullOneFrame(&aPresContext, irs, &complete); + } + + if (nsnull == mPrevInFlow) { + // XXX This is pretty sick, but what we do here is to pull-up, in + // advance, all of the next-in-flows children. We re-resolve their + // style while we are at at it so that when we reflow they have + // the right style. + // + // All of this is so that text-runs reflow properly. + irs.mPrevFrame = mFrames.LastChild(); + for (;;) { + PRBool complete; + nsIFrame* frame = PullOneFrame(&aPresContext, irs, &complete); + if (!frame) { + break; + } + irs.mPrevFrame = frame; + } + irs.mPrevFrame = nsnull; + } + else { +// XXX do this in the Init method instead + // For continuations, we need to check and see if our style + // context is right. If its the same as the first-in-flow, then + // we need to fix it up (that way :first-line style doesn't leak + // into this continuation since we aren't the first line). + nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow(); + if (mStyleContext == first->mStyleContext) { + // Fixup our style context and our children. First get the + // proper parent context. + nsIFrame* parentFrame; + first->GetParent(&parentFrame); + nsIStyleContext* parentContext; + parentFrame->GetStyleContext(&parentContext); + if (parentContext) { + // Create a new style context that is a child of the parent + // style context thus removing the :first-line style. This way + // we behave as if an anonymous (unstyled) span was the child + // of the parent frame. + nsIStyleContext* newSC; + aPresContext.ResolvePseudoStyleContextFor(mContent, + nsHTMLAtoms::mozLineFrame, + parentContext, + PR_FALSE, &newSC); + if (newSC) { + // Switch to the new style context. + SetStyleContext(&aPresContext, newSC); + + // Re-resolve all children + ReParentChildListStyle(&aPresContext, mStyleContext, mFrames); + + NS_RELEASE(newSC); + } + NS_RELEASE(parentContext); + } + } + } + + rv = ReflowFrames(&aPresContext, aReflowState, irs, aMetrics, aStatus); + + // Note: the line layout code will properly compute our + // NS_FRAME_OUTSIDE_CHILDREN state for us. + + return rv; +} + +////////////////////////////////////////////////////////////////////// + nsresult NS_NewPositionedInlineFrame(nsIFrame** aNewFrame) { @@ -224,1950 +1002,9 @@ nsPositionedInlineFrame::Reflow(nsIPresContext& aPresContext, return rv; } -////////////////////////////////////////////////////////////////////// - -// SectionData implementation - -nsInlineFrame::SectionData::SectionData(nsIFrame* aFrameList) -{ - firstBlock = nsnull; - prevFirstBlock = nsnull; - lastBlock = nsnull; - lastFrame = nsnull; - - // Find the first and last block (if any!). When we exit the loop - // lastFrame will be the last frame in aList. - nsIFrame* frame = aFrameList; - firstFrame = aFrameList; - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - if (nsnull == firstBlock) { - prevFirstBlock = lastFrame; - firstBlock = frame; - lastBlock = frame; - } - else { - lastBlock = frame; - } - } - lastFrame = frame; - frame->GetNextSibling(&frame); - } -} - -PRBool -nsInlineFrame::SectionData::SplitFrameList(nsFrameList& aSection1, - nsFrameList& aSection2, - nsFrameList& aSection3) -{ - if (nsnull == firstBlock) { - // There are no blocks - return PR_FALSE; - } - - // We have at least one block - if (nsnull != prevFirstBlock) { - // The first block is not the first frame in aList. Setup section1. - prevFirstBlock->SetNextSibling(nsnull); - aSection1.SetFrames(firstFrame); - } - aSection2.SetFrames(firstBlock); - - if (lastFrame != lastBlock) { - // There are inline frames that follow the last block. Setup section3. - nsIFrame* nextSib; - lastBlock->GetNextSibling(&nextSib); - lastBlock->SetNextSibling(nsnull); - aSection3.SetFrames(nextSib); - } - - return PR_TRUE; -} - -//////////////////////////////////////////////////////////////////////// -// Basic nsInlineFrame methods - -nsresult -NS_NewInlineFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsInlineFrame* it = new nsInlineFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsInlineFrame::nsInlineFrame() -{ -} - -NS_IMETHODIMP -nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - if (nsnull == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kInlineFrameCID)) { - nsInlineFrame* tmp = this; - *aInstancePtr = (void*) tmp; - return NS_OK; - } - return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr); -} - -NS_IMETHODIMP -nsInlineFrame::GetFrameName(nsString& aResult) const -{ - return MakeFrameName("Inline", aResult); -} - -NS_IMETHODIMP -nsInlineFrame::GetFrameType(nsIAtom** aType) const -{ - NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); - *aType = nsLayoutAtoms::inlineFrame; - NS_ADDREF(*aType); - return NS_OK; -} - -NS_IMETHODIMP -nsInlineFrame::Destroy(nsIPresContext& aPresContext) -{ - mFrames.DestroyFrames(aPresContext); - return nsInlineFrameSuper::Destroy(aPresContext); -} - -////////////////////////////////////////////////////////////////////// -// nsInlineFrame child management - -// Find the first inline frame, looking backwards starting at "this", -// that contains an anonymous block. Return nsnull if an anonymous -// block is not found. -nsAnonymousBlockFrame* -nsInlineFrame::FindPrevAnonymousBlock(nsInlineFrame** aBlockParent) -{ - nsInlineFrame* prevInFlow = this; - while (nsnull != prevInFlow) { - // Scan the prev-in-flows frame list, looking for an anonymous - // block frame. - nsIFrame* frame = prevInFlow->mFrames.FirstChild(); - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - *aBlockParent = prevInFlow; - return (nsAnonymousBlockFrame*) frame; - } - frame->GetNextSibling(&frame); - } - prevInFlow = (nsInlineFrame*) prevInFlow->mPrevInFlow; - } - return nsnull; -} - -// Find the first inline frame, looking forwards starting at "this", -// that contains an anonymous block. Return nsnull if an anonymous -// block is not found. -nsAnonymousBlockFrame* -nsInlineFrame::FindAnonymousBlock(nsInlineFrame** aBlockParent) -{ - nsInlineFrame* nextInFlow = this; - while (nsnull != nextInFlow) { - // Scan the prev-in-flows frame list, looking for an anonymous - // block frame. - nsIFrame* frame = nextInFlow->mFrames.FirstChild(); - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - *aBlockParent = nextInFlow; - return (nsAnonymousBlockFrame*) frame; - } - frame->GetNextSibling(&frame); - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - return nsnull; -} - -nsresult -nsInlineFrame::CreateAnonymousBlock(nsIPresContext& aPresContext, - nsIFrame* aInitialFrames, - nsIFrame** aResult) -{ - nsIFrame* bf; - nsresult rv = NS_NewAnonymousBlockFrame(&bf); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr newSC; - aPresContext.ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozAnonymousBlock, - mStyleContext, - PR_FALSE, - getter_AddRefs(newSC)); - rv = bf->Init(aPresContext, mContent, this, newSC, nsnull); - if (NS_FAILED(rv)) { - bf->Destroy(aPresContext); - delete bf; - } - else { - // Set parent for the frames now that the anonymous block has - // been created. - nsIFrame* frame = aInitialFrames; - while (nsnull != frame) { - frame->SetParent(bf); - frame->GetNextSibling(&frame); - } - rv = bf->SetInitialChildList(aPresContext, nsnull, aInitialFrames); - } - *aResult = bf; - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::SetInitialChildList(nsIPresContext& aPresContext, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_UNEXPECTED; - } - if (nsnull == aFrameList) { - return NS_OK; - } - nsCOMPtr shell; - nsresult rv = aPresContext.GetShell(getter_AddRefs(shell)); - if (NS_SUCCEEDED(rv) && shell) { - rv = AppendFrames(aPresContext, *shell, aFrameList, PR_FALSE); - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - if (nsnull == aFrameList) { - return NS_OK; - } - return AppendFrames(aPresContext, aPresShell, aFrameList, PR_TRUE); -} - -nsresult -nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aFrameList, - PRBool aGenerateReflowCommands) -{ -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": append "); - nsFrame::ListTag(stdout, aFrameList); - nsIFrame* lastKid = mFrames.LastChild(); - if (lastKid) { - printf(" after "); - nsFrame::ListTag(stdout, lastKid); - } - printf("\n"); -#endif - - nsresult rv = NS_OK; - SectionData sd(aFrameList); - if (sd.HasABlock()) { - nsFrameList section1, section2, section3; - sd.SplitFrameList(section1, section2, section3); - - // There is at least one block in the new frames. See if there is - // an anonymous block frame in a prev-in-flow of this frame. - nsInlineFrame* prevInline; - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = FindPrevAnonymousBlock(&prevInline); - if (nsnull != anonymousBlock) { - // One of the invariants of nsInlineFrame is that there will be - // at most one anonymous block frame that reflows the - // nsInlineFrame's block children (not counting any - // continuations of the anonymous block frame). - // - // We maintain that invariant by noticing when a new block frame - // enters the list of children and ensuring that all of the - // frames from the first block to the last block are contained - // by the anonymous block (or one of its continuations). This - // can cause some inline frames between here and the inline that - // contains anonymousBlock to have their children stuffed into - // the anonymous block. - - // Build a list of the frames between the anonymous block and - // this frame, stealing children from our continuation frames as - // necessary. - nsIFrame* inlineSiblings; - anonymousBlock->GetNextSibling(&inlineSiblings); - nsFrameList newBlockFrames; - if (nsnull != inlineSiblings) { - newBlockFrames.AppendFrames(anonymousBlock, inlineSiblings); - } - nsInlineFrame* tmp = (nsInlineFrame*) prevInline->mNextInFlow; - while ((nsnull != tmp) && (this != tmp)) { - newBlockFrames.AppendFrames(anonymousBlock, tmp->mFrames); - tmp = (nsInlineFrame*) tmp->mNextInFlow; - } - - // Now tack on all of this frame's child frames (unless this - // frame is the frame that contains the anonymous block) - if (this != prevInline) { - newBlockFrames.AppendFrames(anonymousBlock, mFrames); - } - - // And then append section1 and section2 frames. - if (section1.NotEmpty()) { - newBlockFrames.AppendFrames(anonymousBlock, section1); - } - newBlockFrames.AppendFrames(anonymousBlock, section2); - - // Finally, if there are any frames in section3 then they are - // appended after the anonymous block. These frames will be - // reflowed when they are pushed from the prevInline frame to a - // next-in-flow after the anonymousBlock frame is reflowed. - anonymousBlock->SetNextSibling(section3.FirstChild()); - - // Now we can append the frames to the anonymous block and it - // can generate a reflow command. - rv = anonymousBlock->AppendFrames2(&aPresContext, &aPresShell, nsnull, - newBlockFrames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 1\n"); -#endif - } - else { - // There is no prior block frames that are the children of this - // inline. Therefore, section 1 is appended to our frame list - // and we wrap up the frames in section 2 with a new anonymous - // block and the frames in section 3 get appended to the frame - // list after the anonymous frame (so that they can be pushed to - // a next-in-flow after this finishes reflowing its anonymous - // block). - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, section2.FirstChild(), - &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - if (section1.NotEmpty()) { - mFrames.AppendFrames(nsnull, section1); - } - mFrames.AppendFrame(nsnull, anonBlock); - if (section3.NotEmpty()) { - mFrames.AppendFrames(nsnull, section3); - } -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 2\n"); -#endif - - if (aGenerateReflowCommands) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - } - } - else { - // The new frames contain no block frames - mFrames.AppendFrames(this, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 3\n"); -#endif - - if (aGenerateReflowCommands) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - } - - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - if (nsnull == aFrameList) { - return NS_OK; - } - -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": insert "); - nsFrame::ListTag(stdout, aFrameList); - if (aPrevFrame) { - printf(" after "); - nsFrame::ListTag(stdout, aPrevFrame); - } - printf("\n"); -#endif - - nsresult rv = NS_OK; - SectionData sd(aFrameList); - if (sd.HasABlock()) { - // Break insertion up into 3 pieces - nsFrameList section1, section2, section3; - sd.SplitFrameList(section1, section2, section3); - - nsIFrame* prevFrame = aPrevFrame; - - // First insert the inlines in section1 after prevFrame - if (section1.NotEmpty()) { - nsIFrame* newPrevFrame = section1.LastChild(); - rv = InsertInlineFrames(aPresContext, aPresShell, prevFrame, - section1.FirstChild()); - prevFrame = newPrevFrame; - } - - // Next insert the frames in section2 after prevFrame - if (NS_SUCCEEDED(rv)) { - nsIFrame* newPrevFrame = section2.LastChild(); - rv = InsertBlockFrames(aPresContext, aPresShell, prevFrame, - section2.FirstChild()); - prevFrame = newPrevFrame; - } - - // Finally, insert the frames in section3 after prevFrame - if (NS_SUCCEEDED(rv) && section3.NotEmpty()) { - rv = InsertInlineFrames(aPresContext, aPresShell, prevFrame, - section3.FirstChild()); - } - } - else { - // Use simpler path when the insertion is only inline frames - rv = InsertInlineFrames(aPresContext, aPresShell, aPrevFrame, aFrameList); - } - - return rv; -} - -nsresult -nsInlineFrame::InsertBlockFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - if (nsnull == aPrevFrame) { - // The block is being inserted at the head of all the child - // frames. - nsInlineFrame* flow; - nsAnonymousBlockFrame* anonymousBlock = FindAnonymousBlock(&flow); - if (nsnull == anonymousBlock) { - // There are no anonymous blocks so create one and place the - // frames into it. - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, aFrameList, &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - mFrames.InsertFrames(this, nsnull, anonBlock); - target = this; - generateReflowCommand = PR_TRUE; -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 1\n"); -#endif - } - else { - // Take all of the frames before the anonymous block, plus the - // frames in aFrameList and insert them into the anonymous - // block. - nsFrameList frames; - frames.AppendFrames(anonymousBlock, aFrameList); - nsInlineFrame* start = this; - while (start != flow) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - nsnull, frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 2\n"); -#endif - } - } - else { - // First see if the insertion is inside the anonymous block - nsIFrame* prevFrameParent; - aPrevFrame->GetParent(&prevFrameParent); - if (nsLineLayout::TreatFrameAsBlock(prevFrameParent)) { - // The previous frame's parent is an anonymous block. This means - // that the new block frames can be safely inserted there. - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(prevFrameParent); - frame->GetNextSibling(&frame); - } - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = (nsAnonymousBlockFrame*) prevFrameParent; - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - aPrevFrame, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 3\n"); -#endif - } - else { - // The previous frame's parent is an inline frame. First see if - // there is an anonymous block before the insertion point. - nsInlineFrame* flow = (nsInlineFrame*) prevFrameParent; - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = flow->FindPrevAnonymousBlock(&flow); - if (nsnull != anonymousBlock) { - // We found an anonymous block before the insertion - // point. Take all of the inline frames between the anonymous - // block and prevFrameParent and strip them away from the - // inline frames that contain them. - nsFrameList frames; - nsInlineFrame* start; - flow->GetNextInFlow((nsIFrame**) &start); // start after anon block - while (start != prevFrameParent) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - - // Now append the frames just before and including aPrevFrame - // to "frames". - flow = (nsInlineFrame*) prevFrameParent; - nsIFrame* remainingFrames; - flow->mFrames.Split(aPrevFrame, &remainingFrames); - frames.AppendFrames(anonymousBlock, flow->mFrames); - flow->mFrames.SetFrames(remainingFrames); - generateReflowCommand = PR_TRUE; - target = flow; - - // Finally, append the block frames to "frames" and then - // append the list of frames to the anonymous block. - frames.AppendFrames(anonymousBlock, aFrameList); - anonymousBlock->AppendFrames2(&aPresContext, &aPresShell, nsnull, - frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 4\n"); -#endif - } - else { - // There is no anymous block before the insertion point. See - // if there is one after the insertion point. - flow = (nsInlineFrame*) prevFrameParent; - anonymousBlock = flow->FindAnonymousBlock(&flow); - if (nsnull != anonymousBlock) { - // We found an anonymous block after the insertion - // point. Seed the list of frames to put into the anonymous - // block with the block frames being inserted. - nsFrameList frames; - frames.AppendFrames(anonymousBlock, aFrameList); - nsInlineFrame* start = (nsInlineFrame*) prevFrameParent; - - // Take the frames after aPrevFrame and place them at the - // end of the frames list. - nsIFrame* remainingFrames; - start->mFrames.Split(aPrevFrame, &remainingFrames); - if (remainingFrames) { - frames.AppendFrames(anonymousBlock, remainingFrames); - } - generateReflowCommand = PR_TRUE; - target = start; - - // Gather up all of the inline frames from all of the flow - // between the insertion point and the anonymous block. - start->GetNextInFlow((nsIFrame**) &start); - while (start != flow) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - - // Now update the anonymous block - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - nsnull, frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 5\n"); -#endif - } - else { - // There are no anonymous blocks so create one and place the - // frames into it. - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, aFrameList, &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - - // Insert the frame into the correct parent (it will not be - // this frame when aPrevFrame's parent != this) - flow = (nsInlineFrame*) prevFrameParent; - flow->mFrames.InsertFrames(flow, aPrevFrame, anonBlock); - generateReflowCommand = PR_TRUE; - target = flow; -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 6\n"); -#endif - } - } - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - return rv; -} - -nsresult -nsInlineFrame::InsertInlineFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - if (nsnull == aPrevFrame) { - // Insert the frames at the front of our list. Since the frames - // are all inline frames we just place them there, even if our - // current first frame is the anonymous block frame. The reflow - // logic will properly push the anonymous block frame to a - // next-in-flow. - mFrames.InsertFrames(this, nsnull, aFrameList); - generateReflowCommand = PR_TRUE; - target = this; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 1\n"); -#endif - } - else { - nsIFrame* prevFrameParent; - aPrevFrame->GetParent(&prevFrameParent); - if (nsLineLayout::TreatFrameAsBlock(prevFrameParent)) { - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = (nsAnonymousBlockFrame*) prevFrameParent; - - // The previous frame's parent is an anonymous block (otherwise - // its parent would be this frame). We must not place the inline - // frames into the anonymous block if they should be in - // section3. - nsIFrame* nextSibling; - aPrevFrame->GetNextSibling(&nextSibling); - nsIFrame* anonymousBlockNextInFlow; - prevFrameParent->GetNextInFlow(&anonymousBlockNextInFlow); - if ((nsnull != nextSibling) || (nsnull != anonymousBlockNextInFlow)) { - // Easy case: there are more frames following aPrevFrame which - // means that this insertion lies in the anonymous block. - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(anonymousBlock); - frame->GetNextSibling(&frame); - } - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - aPrevFrame, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 2\n"); -#endif - } - else { - // aPrevFrame is the last frame that should be in the - // anonymous block. - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**)&anonymousBlockParent); - - // Place the inline frames after the anonymous block - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(anonymousBlockParent); - frame->GetNextSibling(&frame); - } - anonymousBlockParent->mFrames.InsertFrames(nsnull, anonymousBlock, - aFrameList); - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 3\n"); -#endif - } - } - else { - // The previous frame's parent is an inline frame. Therefore - // this is either a section1 or section3 insertion. Insert the - // frames in the proper flow block (which will be aPrevFrame's - // parent which is currently stored in anonymousBlock) - nsInlineFrame* flow = (nsInlineFrame*) prevFrameParent; - flow->mFrames.InsertFrames(flow, aPrevFrame, aFrameList); - generateReflowCommand = PR_TRUE; - target = flow; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 4\n"); -#endif - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": remove "); - nsFrame::ListTag(stdout, aOldFrame); - printf("\n"); -#endif - - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - nsIFrame* oldFrameParent; - if (ParentIsInlineFrame(aOldFrame, &oldFrameParent)) { - // Loop and destroy the frame and all of its - // continuations. Because the frame's parent is an inline frame we - // know that any continuations will also be in an inline frame - // parent. - nsInlineFrame* parent = (nsInlineFrame*) oldFrameParent; - while (nsnull != aOldFrame) { - // If the frame being removed has zero size then don't bother - // generating a reflow command. - nsRect bbox; - aOldFrame->GetRect(bbox); - if ((0 == bbox.width) && (0 == bbox.height)) { - // Don't bother generating a reflow command - } - else { - generateReflowCommand = PR_TRUE; - target = this; - } - - // When the parent is an inline frame we have a simple task - - // just remove the frame from its parents list and generate a - // reflow command. - nsIFrame* oldFrameNextInFlow; - aOldFrame->GetNextInFlow(&oldFrameNextInFlow); - nsSplittableType st; - aOldFrame->IsSplittable(st); - if (NS_FRAME_NOT_SPLITTABLE != st) { - nsSplittableFrame::RemoveFromFlow(aOldFrame); - } - parent->mFrames.DestroyFrame(aPresContext, aOldFrame); - aOldFrame = oldFrameNextInFlow; - if (nsnull != aOldFrame) { - aOldFrame->GetParent((nsIFrame**) &parent); - } - } -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 1\n"); -#endif - } - else { -#ifdef DEBUG - nsIFrame* oldFrameNextInFlow; - aOldFrame->GetNextInFlow(&oldFrameNextInFlow); - NS_ASSERTION(nsnull == oldFrameNextInFlow, "XXX: can't remove continued frames that are in anonymous blocks -- not yet implemented"); -#endif - - nsIFrame* nextInFlow; - nsIFrame* prevInFlow; - - // The parent is not an inline frame which means it is an - // anonymous block frame. - nsAnonymousBlockFrame* anonymousBlock = - (nsAnonymousBlockFrame*) oldFrameParent; - - // It is possible that we are about to remove the last child of - // the anonymous block. In this case we remove the anonymous block. - nsIFrame* kids; - anonymousBlock->FirstChild(nsnull, &kids); - nsFrameList blockKids(kids); - if (1 == blockKids.GetLength()) { - // Remove the anonymous block - mFrames.DestroyFrame(aPresContext, anonymousBlock); - generateReflowCommand = PR_TRUE; - target = this; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 2\n"); -#endif - } - else { - // If the frame being removed is a block frame then we may need to - // do something fancy. - if (nsLineLayout::TreatFrameAsBlock(aOldFrame)) { - // It is possible that we are removing the first block in the - // anonymous block or the last block. See if its so. - anonymousBlock->GetPrevInFlow(&prevInFlow); - nsIFrame* prevSib; - if ((nsnull != prevInFlow) || - (nsnull != (prevSib = blockKids.GetPrevSiblingFor(aOldFrame)))) { - // There is a block in the anonymous block prior to the - // block that we are removing. See if we are removing the - // last block in the anonymous block. - anonymousBlock->GetNextInFlow(&nextInFlow); - nsIFrame* nextSib; - aOldFrame->GetNextSibling(&nextSib); - if ((nsnull != nextInFlow) || (nsnull != nextSib)) { - // There is a block in the anonymous block after the block - // that we are removing. This means that we can let the - // anonymous block remove the frame. -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 3\n"); -#endif - anonymousBlock->RemoveFrame2(&aPresContext, &aPresShell, aListName, - aOldFrame); - } - else { - // We are removing the last block. We must steal all of - // the inline frames that preceed the block being removed - // (up to the closest prior block) so that they can be - // moved outside the anonymous block and into an inline - // frame. - - // First get the last frame out of the picture; delete any - // continuations it might have. - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**) &anonymousBlockParent); - nsAnonymousBlockFrame* ab = anonymousBlock; - anonymousBlock->RemoveFramesFrom(aOldFrame); - aOldFrame->Destroy(aPresContext); - while (nsnull != nextInFlow) { - nsIFrame* nextParent; - nextInFlow->GetParent(&nextParent); - if (nextParent != ab) { - ab = (nsAnonymousBlockFrame*) nextParent; - } - ab->RemoveFirstFrame(); - nsIFrame* nextNextInFlow; - nextInFlow->GetNextInFlow(&nextNextInFlow); - nextInFlow->Destroy(aPresContext); - nextInFlow = nextNextInFlow; - } - - // Any inline frames that are between the new last-block - // inside the anonymous block and the block we just - // removed need to be taken out of the anonymous block. - nsFrameList inlines; - while (nsnull != anonymousBlock) { - // Find the first inline before the last block - nsIFrame* abkids; - anonymousBlock->FirstChild(nsnull, &abkids); - if (nsnull != abkids) { - SectionData sd(abkids); - if (sd.HasABlock()) { - abkids = sd.lastBlock; - abkids->GetNextSibling(&abkids); - if (nsnull != abkids) { - // Take the frames that follow the last block - // (which are inline frames) and remove them from - // the anonymous block. Insert them into the - // inlines frame-list. - anonymousBlock->RemoveFramesFrom(abkids); - inlines.InsertFrames(nsnull, nsnull, abkids); - } - } - else { - // All of the frames are inline frames -- take them - // all away. - anonymousBlock->RemoveFramesFrom(abkids); - inlines.InsertFrames(nsnull, nsnull, abkids); - } - } - anonymousBlock->GetPrevInFlow((nsIFrame**) &anonymousBlock); - } - - // Now we have all of the inline frames that need to be - // placed into an inline parent instead of the anonymous - // block parent. - if (inlines.NotEmpty()) { - // Place the inline frames after the anonymous block - // frame in the child list of the anonymousBlockParent. - anonymousBlockParent->mFrames.AppendFrames(anonymousBlockParent, - inlines); - } - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 4\n"); -#endif - } - } - else { - // We are removing the first block child of the anonymous - // block. We must gather all of the inline frames that - // follow the block being removed from the anonymous block - // so that they can be moved outside the anonymous block and - // into an inline frame. - - // Take away the first frame from the anonymous block (which - // is the frame we are trying to remove). Make sure we - // remove aOldFrame's continuations if it has any... - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**) &anonymousBlockParent); - anonymousBlock->RemoveFirstFrame(); - aOldFrame->GetNextInFlow(&nextInFlow); - aOldFrame->Destroy(aPresContext); - while (nsnull != nextInFlow) { - nsIFrame* nextParent; - nextInFlow->GetParent(&nextParent); - if (nextParent != anonymousBlock) { - anonymousBlock = (nsAnonymousBlockFrame*) nextParent; - } - anonymousBlock->RemoveFirstFrame(); - nsIFrame* nextNextInFlow; - nextInFlow->GetNextInFlow(&nextNextInFlow); - nextInFlow->Destroy(aPresContext); - nextInFlow = nextNextInFlow; - } - - // Gather up the inline frames that follow aOldFrame - nsFrameList frames; - PRBool done = PR_FALSE; - while (!done && (nsnull != anonymousBlock)) { - nsIFrame* kid; - anonymousBlock->FirstChild(nsnull, &kid); - while (nsnull != kid) { - if (nsLineLayout::TreatFrameAsBlock(kid)) { - done = PR_TRUE; - break; - } - nsIFrame* next; - kid->GetNextSibling(&next); - anonymousBlock->RemoveFirstFrame(); - frames.AppendFrame(nsnull, kid); - kid = next; - } - anonymousBlock->GetNextInFlow((nsIFrame**) &anonymousBlock); - } - - if (frames.NotEmpty()) { - // If the anonymousBlockParent has a prev-in-flow then - // append the inline frames there, otherwise insert them - // before the anonymousBlock. - anonymousBlockParent->GetPrevInFlow(&prevInFlow); - if (nsnull != prevInFlow) { - anonymousBlockParent = (nsInlineFrame*) prevInFlow; - anonymousBlockParent->mFrames.AppendFrames(anonymousBlockParent, - frames); - } - else { - anonymousBlockParent->mFrames.InsertFrames(anonymousBlockParent, - nsnull, - frames); - } - } - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 5\n"); -#endif - } - } - else { - // We can let the anonymousBlock remove the frame directly -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 6\n"); -#endif - anonymousBlock->RemoveFrame2(&aPresContext, &aPresShell, aListName, - aOldFrame); - } - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// -// Reflow methods - -NS_IMETHODIMP -nsInlineFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - if (nsnull == aReflowState.mLineLayout) { - return NS_ERROR_INVALID_ARG; - } - DrainOverflow(&aPresContext); - - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; - return NS_OK; - } - - // Set our own reflow state (additional state above and beyond - // aReflowState) - InlineReflowState irs; - irs.mPrevFrame = nsnull; - irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; - irs.mNextRCFrame = nsnull; - if (eReflowReason_Incremental == aReflowState.reason) { - // Peel off the next frame in the path if this is an incremental - // reflow aimed at one of the children. - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this != target) { - aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); - } - } - - nsresult rv; - if (mFrames.IsEmpty()) { - // Try to pull over one frame before starting so that we know - // whether we have an anonymous block or not. - (void) PullAnyFrame(&aPresContext, irs); - } - - if (HaveAnonymousBlock()) { - if (!aReflowState.mLineLayout->LineIsEmpty()) { - // This inline frame cannot be placed on the current line - // because there already is an inline frame on this line (and we - // contain an anonymous block). - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - rv = NS_OK; - } - else { - rv = ReflowBlockFrame(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear - // it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - } - } - else { - rv = ReflowInlineFrames(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - // Note: when we are reflowing inline frames the line layout code - // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for - // us. - } - - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) -{ - if (HaveAnonymousBlock()) { - aLineLayout.EndTextRun(); - } - else { - nsIFrame* frame = mFrames.FirstChild(); - while (nsnull != frame) { - frame->FindTextRuns(aLineLayout); - frame->GetNextSibling(&frame); - } - } - return NS_OK; -} - -void -nsInlineFrame::DrainOverflow(nsIPresContext* aPresContext) -{ - // Check for an overflow list with our prev-in-flow - nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; - if (nsnull != prevInFlow) { - nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); - - if (prevOverflowFrames) { - // When pushing and pulling frames we need to check for whether any - // views need to be reparented. - for (nsIFrame* f = prevOverflowFrames; f; f->GetNextSibling(&f)) { - nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevInFlow, this); - } - mFrames.InsertFrames(this, nsnull, prevOverflowFrames); - } - } - - // It's also possible that we have an overflow list for ourselves - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); - if (overflowFrames) { - NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); - mFrames.AppendFrames(nsnull, overflowFrames); - } -} - -nsresult -nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; - aStatus = NS_FRAME_COMPLETE; - - nsLineLayout* lineLayout = aReflowState.mLineLayout; - nscoord leftEdge = 0; - if (nsnull == mPrevInFlow) { - leftEdge = aReflowState.mComputedBorderPadding.left; - } - nscoord availableWidth = aReflowState.availableWidth; - if (NS_UNCONSTRAINEDSIZE != availableWidth) { - // Subtract off left and right border+padding from availableWidth - availableWidth -= leftEdge; - availableWidth -= aReflowState.mComputedBorderPadding.right; - } - lineLayout->BeginSpan(this, &aReflowState, - leftEdge, leftEdge + availableWidth); - - // First reflow our current children - nsIFrame* frame = mFrames.FirstChild(); - PRBool done = PR_FALSE; - while (nsnull != frame) { - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); - if (NS_FAILED(rv)) { - done = PR_TRUE; - break; - } - if (NS_FRAME_COMPLETE != aStatus) { - if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { - done = PR_TRUE; - break; - } - } - irs.mPrevFrame = frame; - frame->GetNextSibling(&frame); - } - - // Attempt to pull frames from our next-in-flow until we can't - if (!done && (nsnull != mNextInFlow)) { - while (!done) { - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - PRBool isComplete; - frame = PullInlineFrame(aPresContext, irs, &isComplete); - if (nsnull == frame) { - if (!isComplete) { - aStatus = NS_FRAME_NOT_COMPLETE; - } - break; - } - rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); - if (NS_FAILED(rv)) { - done = PR_TRUE; - break; - } - if (NS_FRAME_COMPLETE != aStatus) { - if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { - done = PR_TRUE; - break; - } - } - irs.mPrevFrame = frame; - } - } -#ifdef DEBUG - if (NS_FRAME_COMPLETE == aStatus) { - // We can't be complete AND have overflow frames! - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE); - NS_ASSERTION(!overflowFrames, "whoops"); - } -#endif - - // If after reflowing our children they take up no area then make - // sure that we don't either. - // - // Note: CSS demands that empty inline elements still affect the - // line-height calculations. However, continuations of an inline - // that are empty we force to empty so that things like collapsed - // whitespace in an inline element don't affect the line-height. - nsSize size; - lineLayout->EndSpan(this, size, aMetrics.maxElementSize); - if ((0 == size.height) && (0 == size.width) && - ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { - // This is a continuation of a previous inline. Therefore make - // sure we don't affect the line-height. - aMetrics.width = 0; - aMetrics.height = 0; - aMetrics.ascent = 0; - aMetrics.descent = 0; - if (nsnull != aMetrics.maxElementSize) { - aMetrics.maxElementSize->width = 0; - aMetrics.maxElementSize->height = 0; - } - } - else { - // Compute final width - aMetrics.width = size.width; - if (nsnull == mPrevInFlow) { - aMetrics.width += aReflowState.mComputedBorderPadding.left; - } - if (NS_FRAME_IS_COMPLETE(aStatus)) { - aMetrics.width += aReflowState.mComputedBorderPadding.right; - } - - const nsStyleFont* font; - GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); - aReflowState.rendContext->SetFont(font->mFont); - nsCOMPtr fm; - aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); - - // Compute final height of the frame. - // - // Do things the standard css2 way -- though it's hard to find it - // in the css2 spec! It's actually found in the css1 spec section - // 4.4 (you will have to read between the lines to really see - // it). - // - // The height of our box is the sum of our font size plus the top - // and bottom border and padding. The height of children do not - // affect our height. - fm->GetMaxAscent(aMetrics.ascent); - fm->GetMaxDescent(aMetrics.descent); - fm->GetHeight(aMetrics.height); - aMetrics.ascent += aReflowState.mComputedBorderPadding.top; - aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; - aMetrics.height += aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; - - // Note: we normally use the actual font height for computing the - // line-height raw value from the style context. On systems where - // they disagree the actual font height is more appropriate. This - // little hack lets us override that behavior to allow for more - // precise layout in the face of imprecise fonts. - if (nsHTMLReflowState::UseComputedHeight()) { - aMetrics.height = font->mFont.size + - aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; - } - } - - // For now our combined area is zero. The real value will be - // computed during vertical alignment of the line we are on. - aMetrics.mCombinedArea.x = 0; - aMetrics.mCombinedArea.y = 0; - aMetrics.mCombinedArea.width = aMetrics.width; - aMetrics.mCombinedArea.height = aMetrics.height; - -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": metrics=%d,%d ascent=%d descent=%d\n", - aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); -#endif - - return rv; -} - -nsresult -nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsIFrame* aFrame, - nsReflowStatus& aStatus) -{ - // Make sure that we don't reflow a block frame when we run across - // one. This can easily happen if this inline has a mixture of - // frames (note that an anonymous block frame is used to wrap up the - // direct block children of this inline therefore when we do run - // across a block frame its an anonymous block). - if (nsLineLayout::TreatFrameAsBlock(aFrame)) { - NS_ASSERTION(aFrame != mFrames.FirstChild(), "bad anon-block status"); - PushFrames(aPresContext, aFrame, irs.mPrevFrame); - aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_NOT_COMPLETE); - return NS_OK; - } - - nsLineLayout* lineLayout = aReflowState.mLineLayout; - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); - if (NS_FAILED(rv)) { - return rv; - } - if (NS_INLINE_IS_BREAK(aStatus)) { - if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { - if (aFrame != mFrames.FirstChild()) { - // Change break-before status into break-after since we have - // already placed at least one child frame. This preserves the - // break-type so that it can be propogated upward. - aStatus = NS_FRAME_NOT_COMPLETE | - NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | - (aStatus & NS_INLINE_BREAK_TYPE_MASK); - PushFrames(aPresContext, aFrame, irs.mPrevFrame); - } - else { - // Preserve reflow status when breaking-before our first child - // and propogate it upward without modification. - } - } - else { - // Break-after - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - } - nsIFrame* nextFrame; - aFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - aStatus |= NS_FRAME_NOT_COMPLETE; - PushFrames(aPresContext, nextFrame, aFrame); - } - else if (nsnull != mNextInFlow) { - // We must return an incomplete status if there are more child - // frames remaining in a next-in-flow that follows this frame. - nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->mFrames.NotEmpty()) { - aStatus |= NS_FRAME_NOT_COMPLETE; - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - } - } - } - else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - if (!reflowingFirstLetter) { - nsIFrame* nextFrame; - aFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - PushFrames(aPresContext, nextFrame, aFrame); - } - } - } - return rv; -} - -nsIFrame* -nsInlineFrame::PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& irs, - PRBool* aIsComplete) -{ - PRBool isComplete = PR_TRUE; - - nsIFrame* frame = nsnull; - nsInlineFrame* nextInFlow = irs.mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->HaveAnonymousBlock()) { - isComplete = PR_FALSE; - break; - } - frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); - if (nsnull != frame) { - isComplete = PR_FALSE; - nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - irs.mNextInFlow = nextInFlow; - } - - *aIsComplete = isComplete; - return frame; -} - -nsIFrame* -nsInlineFrame::PullAnyFrame(nsIPresContext* aPresContext, - InlineReflowState& irs) -{ - nsIFrame* frame = nsnull; - nsInlineFrame* nextInFlow = irs.mNextInFlow; - while (nsnull != nextInFlow) { - frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); - if (nsnull != frame) { - nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); - break; - } - - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - irs.mNextInFlow = nextInFlow; - } - - return frame; -} - -void -nsInlineFrame::PushFrames(nsIPresContext* aPresContext, - nsIFrame* aFromChild, - nsIFrame* aPrevSibling) -{ - NS_PRECONDITION(nsnull != aFromChild, "null pointer"); - NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); -#ifdef DEBUG - nsIFrame* prevNextSibling; - aPrevSibling->GetNextSibling(&prevNextSibling); - NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); -#endif - - // Disconnect aFromChild from its previous sibling - aPrevSibling->SetNextSibling(nsnull); - - // Add the frames to our overflow list (let our next in flow drain - // our overflow list when it is ready) - SetOverflowFrames(aPresContext, aFromChild); -} - -nsresult -nsInlineFrame::ReflowBlockFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus) -{ - nsIFrame* blockFrame = mFrames.FirstChild(); - - // Compute available area -#if XXX_what_to_do - nscoord x = aReflowState.mComputedBorderPadding.left; - nscoord availableWidth = aReflowState.availableWidth; - if (NS_UNCONSTRAINEDSIZE != availableWidth) { - if (nsnull != mPrevInFlow) { - x = 0; - availableWidth -= aReflowState.mComputedBorderPadding.right; - } - else { - availableWidth -= aReflowState.mComputedBorderPadding.left + - aReflowState.mComputedBorderPadding.right; - } - } - nscoord y = aReflowState.mComputedBorderPadding.top; - nscoord availableHeight = aReflowState.availableHeight; - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) { - availableHeight -= aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.right; - } -#else - nscoord x = 0; - nscoord availableWidth = aReflowState.availableWidth; - nscoord y = 0; - nscoord availableHeight = aReflowState.availableHeight; -#endif - - // XXX_ib write me... -//XXX nscoord collapsedTopMargin = 0; - nscoord collapsedBottomMargin = 0; - - // Reflow the block frame - nsBlockReflowContext bc(aPresContext, aReflowState, - nsnull != aMetrics.maxElementSize); - bc.SetNextRCFrame(irs.mNextRCFrame); - nsRect availSpace(x, y, availableWidth, availableHeight); - PRBool isAdjacentWithTop = PR_FALSE; - nsMargin computedOffsets; - nsresult rv = bc.ReflowBlock(blockFrame, availSpace, PR_FALSE, 0, - isAdjacentWithTop, - computedOffsets, aStatus); - if (NS_FAILED(rv)) { - return rv; - } - if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { - // We need to break before placing the block so propogate that - // status outward to our parent. - } - else { - // Place the block (during placement we might discover that none - // of it fits) - nsRect bounds; - PRBool anyFit = bc.PlaceBlock(isAdjacentWithTop, - computedOffsets, &collapsedBottomMargin, - bounds, aMetrics.mCombinedArea); - if (!anyFit) { - // None of the block fit - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - } - else { - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - // When the block isn't complete create a continuation for it - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, blockFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - } - - // It's possible that the block frame is followed by one or more - // inline frames. Make sure we reflect that in our reflow status - // and push them to our next-in-flow. - nsIFrame* nextFrame; - blockFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - PushFrames(aPresContext, nextFrame, blockFrame); - aStatus |= NS_FRAME_NOT_COMPLETE; - } - else if (NS_FRAME_IS_COMPLETE(aStatus)) { - // When the block we reflowed is complete then we need to - // check and see if there are other frames (inline frames) - // following in our continuations so that we return the proper - // reflow status. - nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->mFrames.NotEmpty() || - nextInFlow->GetOverflowFrames(aPresContext, PR_FALSE)) { - aStatus |= NS_FRAME_NOT_COMPLETE; - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - } - - // What we do here is to fudge the size. This frame will - // be 0,0 but will contain a single child (the anonymous block) - // that is properly sized. - aMetrics.width = bounds.width; - aMetrics.height = bounds.height; - aMetrics.ascent = bounds.height; - aMetrics.descent = 0; - aMetrics.mCarriedOutBottomMargin = bc.GetCarriedOutBottomMargin(); - if (nsnull != aMetrics.maxElementSize) { - *aMetrics.maxElementSize = bc.GetMaxElementSize(); - } - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// - -PRIntn -nsInlineFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow; - if (prev->mRect.height || prev->mRect.width) { - // Prev-in-flow is not empty therefore we don't render our left - // border edge. - skip |= 1 << NS_SIDE_LEFT; - } - else { - // If the prev-in-flow is empty, then go ahead and let our right - // edge border render. - } - } - if (nsnull != mNextInFlow) { - nsInlineFrame* next = (nsInlineFrame*) mNextInFlow; - if (next->mRect.height || next->mRect.width) { - // Next-in-flow is not empty therefore we don't render our right - // border edge. - skip |= 1 << NS_SIDE_RIGHT; - } - else { - // If the next-in-flow is empty, then go ahead and let our right - // edge border render. - } - } - return skip; -} - -////////////////////////////////////////////////////////////////////// - -// nsLineFrame implementation - -static void -ReParentChildListStyle(nsIPresContext* aPresContext, - nsIStyleContext* aParentStyleContext, - nsFrameList& aFrameList) -{ - nsIFrame* kid = aFrameList.FirstChild(); - while (nsnull != kid) { - aPresContext->ReParentStyleContext(kid, aParentStyleContext); - kid->GetNextSibling(&kid); - } -} - -nsresult -NS_NewFirstLineFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsInlineFrame* it = new nsFirstLineFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsFirstLineFrame::nsFirstLineFrame() -{ -} - -NS_IMETHODIMP -nsFirstLineFrame::GetFrameName(nsString& aResult) const -{ - return MakeFrameName("Line", aResult); -} - -NS_IMETHODIMP -nsFirstLineFrame::GetFrameType(nsIAtom** aType) const -{ - NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); - *aType = nsLayoutAtoms::lineFrame; - NS_ADDREF(*aType); - return NS_OK; -} - -NS_IMETHODIMP -nsFirstLineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -#else - nsresult rv = nsInlineFrame::AppendFrames(aPresContext, aPresShell, - aListName, aFrameList); -// nsFrameList frames(aFrameList); -// ReResolveChildList(&aPresContext, mStyleContext, frames); - return rv; -#endif -} - -NS_IMETHODIMP -nsFirstLineFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -#else - nsresult rv = nsInlineFrame::InsertFrames(aPresContext, aPresShell, - aListName, aPrevFrame, aFrameList); -// nsFrameList frames(aFrameList); -// ReResolveChildList(&aPresContext, mStyleContext, frames); - return rv; -#endif -} - -NS_IMETHODIMP -nsFirstLineFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -#else - nsresult rv = nsInlineFrame::RemoveFrame(aPresContext, aPresShell, - aListName, aOldFrame); - return rv; -#endif -} - -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsFirstLineFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIFrame* aFrameList) -{ - nsFrameList frames(aFrameList); - ReParentChildListStyle(aPresContext, mStyleContext, frames); - // XXX ReparentFrameView - mFrames.AppendFrames(this, aFrameList); - return NS_OK; -} - -nsresult -nsFirstLineFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsFrameList frames(aFrameList); - ReParentChildListStyle(aPresContext, mStyleContext, frames); - // XXX ReparentFrameView - mFrames.InsertFrames(this, aPrevFrame, aFrameList); - return NS_OK; -} - -nsresult -nsFirstLineFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIFrame* aOldFrame) -{ - nsIFrame* nextInFlow; - aOldFrame->GetNextInFlow(&nextInFlow); - if (nextInFlow) { - DeleteChildsNextInFlow(*aPresContext, aOldFrame); - } - mFrames.RemoveFrame(aOldFrame); - return NS_OK; -} -#endif - -void -nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame) -{ - nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame); - if (prevFrame) { - prevFrame->SetNextSibling(nsnull); - } - else { - mFrames.SetFrames(nsnull); - } -} - -nsIFrame* -nsFirstLineFrame::PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& irs, - PRBool* aIsComplete) -{ - nsIFrame* frame = - nsInlineFrame::PullInlineFrame(aPresContext, irs, aIsComplete); - if (frame && !mPrevInFlow) { - // We are a first-line frame. Fixup the child frames - // style-context that we just pulled. - aPresContext->ReParentStyleContext(frame, mStyleContext); - } - return frame; -} - -void -nsFirstLineFrame::DrainOverflow(nsIPresContext* aPresContext) -{ - // Check for an overflow list with our prev-in-flow - nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow; - if (nsnull != prevInFlow) { - nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); - if (prevOverflowFrames) { - nsFrameList frames(prevOverflowFrames); - - ReParentChildListStyle(aPresContext, mStyleContext, frames); - mFrames.InsertFrames(this, nsnull, prevOverflowFrames); - } - } - - // It's also possible that we have an overflow list for ourselves - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); - if (overflowFrames) { - NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); - nsFrameList frames(overflowFrames); - - ReParentChildListStyle(aPresContext, mStyleContext, frames); - mFrames.AppendFrames(nsnull, overflowFrames); - } -} - -NS_IMETHODIMP -nsFirstLineFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - if (nsnull == aReflowState.mLineLayout) { - return NS_ERROR_INVALID_ARG; - } - DrainOverflow(&aPresContext); - - // Set our own reflow state (additional state above and beyond - // aReflowState) - InlineReflowState irs; - irs.mPrevFrame = nsnull; - irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; - irs.mNextRCFrame = nsnull; - if (eReflowReason_Incremental == aReflowState.reason) { - // Peel off the next frame in the path if this is an incremental - // reflow aimed at one of the children. - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this != target) { - aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); - } - } - - nsresult rv; - PRBool wasEmpty = mFrames.IsEmpty(); - if (wasEmpty) { - // Try to pull over one frame before starting so that we know - // whether we have an anonymous block or not. - PullAnyFrame(&aPresContext, irs); - } - - if (HaveAnonymousBlock()) { - if (!aReflowState.mLineLayout->LineIsEmpty()) { - // This inline frame cannot be placed on the current line - // because there already is an inline frame on this line (and we - // contain an anonymous block). - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - rv = NS_OK; - } - else { - rv = ReflowBlockFrame(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear - // it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - } - } - else { - if (wasEmpty) { - // Fixup style of frame just pulled up - nsIFrame* firstFrame = mFrames.FirstChild(); - if (firstFrame) { - aPresContext.ReParentStyleContext(firstFrame, mStyleContext); - } - } - if (nsnull == mPrevInFlow) { - // XXX This is pretty sick, but what we do here is to pull-up, in - // advance, all of the next-in-flows children. We re-resolve their - // style while we are at at it so that when we reflow they have - // the right style. - // - // All of this is so that text-runs reflow properly. - irs.mPrevFrame = mFrames.LastChild(); - for (;;) { - PRBool complete; - nsIFrame* frame = PullInlineFrame(&aPresContext, irs, &complete); - if (!frame) { - break; - } - irs.mPrevFrame = frame; - } - irs.mPrevFrame = nsnull; - } - else { -// XXX do this in the Init method instead - // For continuations, we need to check and see if our style - // context is right. If its the same as the first-in-flow, then - // we need to fix it up (that way :first-line style doesn't leak - // into this continuation since we aren't the first line). - nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow(); - if (mStyleContext == first->mStyleContext) { - // Fixup our style context and our children. First get the - // proper parent context. - nsIFrame* parentFrame; - first->GetParent(&parentFrame); - nsIStyleContext* parentContext; - parentFrame->GetStyleContext(&parentContext); - if (parentContext) { - // Create a new style context that is a child of the parent - // style context thus removing the :first-line style. This way - // we behave as if an anonymous (unstyled) span was the child - // of the parent frame. - nsIStyleContext* newSC; - aPresContext.ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozLineFrame, - parentContext, - PR_FALSE, &newSC); - if (newSC) { - // Switch to the new style context. - SetStyleContext(&aPresContext, newSC); - - // Re-resolve all children - ReParentChildListStyle(&aPresContext, mStyleContext, mFrames); - - NS_RELEASE(newSC); - } - NS_RELEASE(parentContext); - } - } - } - - rv = ReflowInlineFrames(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - // Note: when we are reflowing inline frames the line layout code - // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for - // us. - } - - return rv; -} - #ifdef DEBUG NS_IMETHODIMP -nsPositionedInlineFrame::SizeOf(nsISizeOfHandler* aHandler, - PRUint32* aResult) const +nsPositionedInlineFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const { if (!aResult) { return NS_ERROR_NULL_POINTER; diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 7a55d14fd266..2fcd9f0ddaca 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -30,6 +30,12 @@ class nsAnonymousBlockFrame; #define nsInlineFrameSuper nsHTMLContainerFrame +/** + * Inline frame class. + * + * This class manages a list of child frames that are inline frames. Working with + * nsLineLayout, the class will reflow and place inline frames on a line. + */ class nsInlineFrame : public nsInlineFrameSuper { public: @@ -39,9 +45,6 @@ public: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); // nsIFrame overrides - NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList); NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, @@ -55,7 +58,11 @@ public: nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame); - NS_IMETHOD Destroy(nsIPresContext& aPresContext); + NS_IMETHOD ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame); NS_IMETHOD GetFrameName(nsString& aResult) const; NS_IMETHOD GetFrameType(nsIAtom** aType) const; @@ -65,15 +72,15 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout); -#if XXX_fix_me - NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace); - NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext, - nsIRenderingContext& aRC, - nscoord& aDeltaWidth); -#endif static nsIID kInlineFrameCID; + // Take all of the frames away from this frame. The caller is + // presumed to keep them alive. + void StealAllFrames() { + mFrames.SetFrames(nsnull); + } + protected: // Additional reflow state used during our reflow methods struct InlineReflowState { @@ -82,75 +89,15 @@ protected: nsInlineFrame* mNextInFlow; }; - // A helper class that knows how to take a list of frames and chop - // it up into 3 sections. - struct SectionData { - SectionData(nsIFrame* aFrameList); - - PRBool SplitFrameList(nsFrameList& aSection1, - nsFrameList& aSection2, - nsFrameList& aSection3); - - PRBool HasABlock() const { - return nsnull != firstBlock; - } - - nsIFrame* firstBlock; - nsIFrame* prevFirstBlock; - nsIFrame* lastBlock; - nsIFrame* firstFrame; - nsIFrame* lastFrame; - }; - nsInlineFrame(); virtual PRIntn GetSkipSides() const; - PRBool HaveAnonymousBlock() const { - return mFrames.NotEmpty() - ? nsLineLayout::TreatFrameAsBlock(mFrames.FirstChild()) - : PR_FALSE; - } - - static PRBool ParentIsInlineFrame(nsIFrame* aFrame, nsIFrame** aParent) { - void* tmp; - nsIFrame* parent; - aFrame->GetParent(&parent); - *aParent = parent; - if (NS_SUCCEEDED(parent->QueryInterface(kInlineFrameCID, &tmp))) { - return PR_TRUE; - } - return PR_FALSE; - } - - nsAnonymousBlockFrame* FindPrevAnonymousBlock(nsInlineFrame** aBlockParent); - - nsAnonymousBlockFrame* FindAnonymousBlock(nsInlineFrame** aBlockParent); - - nsresult CreateAnonymousBlock(nsIPresContext& aPresContext, - nsIFrame* aFrameList, - nsIFrame** aResult); - - nsresult AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aFrameList, - PRBool aGenerateReflowCommands); - - nsresult InsertBlockFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult InsertInlineFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult ReflowInlineFrames(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& rs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus); + nsresult ReflowFrames(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& rs, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); nsresult ReflowInlineFrame(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -158,29 +105,23 @@ protected: nsIFrame* aFrame, nsReflowStatus& aStatus); - virtual nsIFrame* PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& rs, - PRBool* aIsComplete); + virtual nsIFrame* PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& rs, + PRBool* aIsComplete); virtual void PushFrames(nsIPresContext* aPresContext, nsIFrame* aFromChild, nsIFrame* aPrevSibling); virtual void DrainOverflow(nsIPresContext* aPresContext); - - nsIFrame* PullAnyFrame(nsIPresContext* aPresContext, InlineReflowState& rs); - - nsresult ReflowBlockFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& rs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus); }; //---------------------------------------------------------------------- -// Variation on inline-frame used to manage lines for line layout in -// special situations. +/** + * Variation on inline-frame used to manage lines for line layout in + * special situations (:first-line style in particular). + */ class nsFirstLineFrame : public nsInlineFrame { public: friend nsresult NS_NewFirstLineFrame(nsIFrame** aNewFrame); @@ -192,62 +133,20 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); -#ifdef BLOCK_DOES_FIRST_LINE - // AppendFrames/InsertFrames/RemoveFrame are implemented to forward - // the method call to the parent frame. -#endif - NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - -#ifdef BLOCK_DOES_FIRST_LINE - // These methods are used by the parent frame to actually modify the - // child frames of the line frame. These methods do not generate - // reflow commands. - nsresult AppendFrames2(nsIPresContext* aPresContext, - nsIFrame* aFrameList); - - nsresult InsertFrames2(nsIPresContext* aPresContext, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult RemoveFrame2(nsIPresContext* aPresContext, - nsIFrame* aOldFrame); - -#endif // Take frames starting at aFrame until the end of the frame-list // away from this frame. The caller is presumed to keep them alive. void StealFramesFrom(nsIFrame* aFrame); - // Take all of the frames away from this frame. The caller is - // presumed to keep them alive. - void StealAllFrames() { - mFrames.SetFrames(nsnull); - } - protected: nsFirstLineFrame(); - virtual nsIFrame* PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& rs, - PRBool* aIsComplete); + virtual nsIFrame* PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& rs, + PRBool* aIsComplete); virtual void DrainOverflow(nsIPresContext* aPresContext); }; -extern nsresult NS_NewFirstLineFrame(nsIFrame** aNewFrame); - - //---------------------------------------------------------------------- // Derived class created for relatively positioned inline-level elements diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/html/base/src/nsBlockFrame.h b/layout/html/base/src/nsBlockFrame.h index b9a35c5a3ce3..aabaf7359048 100644 --- a/layout/html/base/src/nsBlockFrame.h +++ b/layout/html/base/src/nsBlockFrame.h @@ -40,9 +40,6 @@ class nsFirstLineFrame; */ #define NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET 0x80000000 #define NS_BLOCK_IS_HTML_PARAGRAPH 0x40000000 -#ifdef BLOCK_DOES_FIRST_LINE -#define NS_BLOCK_HAS_FIRST_LINE_STYLE 0x20000000 -#endif #define NS_BLOCK_HAS_FIRST_LETTER_STYLE 0x10000000 #define nsBlockFrameSuper nsHTMLContainerFrame @@ -146,10 +143,6 @@ protected: nsIStyleContext* GetFirstLetterStyle(nsIPresContext* aPresContext); -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* GetFirstLineStyle(nsIPresContext* aPresContext); -#endif - void SetFlags(PRUint32 aFlags) { mFlags = aFlags; } @@ -173,22 +166,6 @@ protected: nsIFrame* aFrameList, nsIFrame* aPrevSibling); -#ifdef BLOCK_DOES_FIRST_LINE - nsresult AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling); - - nsIFrame* TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid); - - nsresult RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame); - - nsresult WrapFramesInFirstLineFrame(nsIPresContext* aPresContext); -#endif - void FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame); nsresult DoRemoveFrame(nsIPresContext* aPresContext, @@ -381,72 +358,5 @@ protected: friend class nsBlockReflowState; }; -//---------------------------------------------------------------------- - -#define nsAnonymousBlockFrameSuper nsBlockFrame - -// Anonymous block frame. An anonymous block is used by some other -// container (the parent frame) to provide block reflow for a set of -// child frames. The parent is responsible for the maintainance of the -// anonymous blocks child list. To accomplish this, the normal methods -// for managing the child list (AppendFrames, InsertFrames, and -// RemoveFrame) forward the operation to the parent frame (the -// container of the anonymous block). -class nsAnonymousBlockFrame : public nsAnonymousBlockFrameSuper { -public: - friend nsresult NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame); - - // nsIFrame overrides - - // AppendFrames/InsertFrames/RemoveFrame are implemented to forward - // the method call to the parent frame. - NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - - // These methods are used by the parent frame to actually modify the - // child frames of the anonymous block frame. - nsresult AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - - nsresult InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - - // Take the first frame away from the anonymous block frame. The - // caller is responsible for the first frames final disposition - // (e.g. deleting it if it wants to). - void RemoveFirstFrame(); - - // Remove from the blocks list of children the frames starting at - // aFrame until the end of the child list. The caller is responsible - // for the first frames final disposition (e.g. deleting it if it - // wants to). - void RemoveFramesFrom(nsIFrame* aFrame); - -protected: - nsAnonymousBlockFrame(); - ~nsAnonymousBlockFrame(); -}; - #endif /* nsBlockFrame_h___ */ diff --git a/layout/html/base/src/nsBlockReflowState.cpp b/layout/html/base/src/nsBlockReflowState.cpp index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/html/base/src/nsBlockReflowState.cpp +++ b/layout/html/base/src/nsBlockReflowState.cpp @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/html/base/src/nsBlockReflowState.h b/layout/html/base/src/nsBlockReflowState.h index 974f0a4b354a..7e1ffee39b89 100644 --- a/layout/html/base/src/nsBlockReflowState.h +++ b/layout/html/base/src/nsBlockReflowState.h @@ -3746,21 +3746,12 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // line and don't stop the line reflow... PRBool splitLine = !reflowingFirstLetter; if (reflowingFirstLetter) { -#ifdef BLOCK_DOES_FIRST_LINE - if (aLine->IsFirstLine()) { + nsCOMPtr frameType; + aFrame->GetFrameType(getter_AddRefs(frameType)); + if ((nsLayoutAtoms::inlineFrame == frameType.get()) || + (nsLayoutAtoms::lineFrame == frameType.get())) { splitLine = PR_TRUE; } - else -#endif - { - nsIAtom* frameType; - if (NS_SUCCEEDED(aFrame->GetFrameType(&frameType)) && frameType) { - if (frameType == nsLayoutAtoms::inlineFrame) { - splitLine = PR_TRUE; - } - NS_RELEASE(frameType); - } - } } if (splitLine) { @@ -4281,100 +4272,6 @@ nsBlockFrame::LastChild() return nsnull; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::WrapFramesInFirstLineFrame(nsIPresContext* aPresContext) -{ - nsLineBox* line = mLines; - if (!line) { - return NS_OK; - } - - // Find the first and last inline line that has frames that aren't - // yet in the first-line-frame. - nsLineBox* prevLine = nsnull; - nsIFrame* firstInlineFrame = nsnull; - nsFirstLineFrame* lineFrame = nsnull; - nsIFrame* nextSib = nsnull; - nsresult rv = NS_OK; - while (line) { - if (line->IsBlock()) { - nextSib = line->mFirstChild; - break; - } - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->mChildCount, "bad first line"); - lineFrame = (nsFirstLineFrame*) line->mFirstChild; - prevLine = line; - line = line->mNext; - } - else { - if (!firstInlineFrame) { - firstInlineFrame = line->mFirstChild; - } - if (prevLine) { - prevLine->mNext = line->mNext; - delete line; - line = prevLine->mNext; - } - else { - prevLine = line; - line = line->mNext; - } - } - } - if (!firstInlineFrame) { - // All of the inline frames are already where they should be - return NS_OK; - } - - // Make the last inline frame thats going into the first-line-frame - // have no next sibling. - if (line) { - nsFrameList frames(firstInlineFrame); - nsIFrame* lastInlineFrame = frames.GetPrevSiblingFor(line->mFirstChild); - lastInlineFrame->SetNextSibling(nsnull); - } - - // If there is no first-line-frame currently, we create it - if (!lineFrame) { - nsIStyleContext* firstLineStyle = GetFirstLineStyle(aPresContext); - - // Create line frame - rv = NS_NewFirstLineFrame((nsIFrame**) &lineFrame); - if (NS_FAILED(rv)) { - return rv; - } - rv = lineFrame->Init(*aPresContext, mContent, this, - firstLineStyle, nsnull); - if (NS_FAILED(rv)) { - return rv; - } - line = mLines; - line->mFirstChild = lineFrame; - line->mChildCount = 1; - line->SetIsFirstLine(PR_TRUE); - - NS_RELEASE(firstLineStyle); - } - - // Connect last first-line-frame to the remaining frames - lineFrame->SetNextSibling(nextSib); - - // Put the new children into the line-frame - lineFrame->AppendFrames2(aPresContext, firstInlineFrame); - - // Mark the first-line frames dirty - line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - - return rv; -} -#endif - NS_IMETHODIMP nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, @@ -4399,14 +4296,6 @@ nsBlockFrame::AppendFrames(nsIPresContext& aPresContext, nsLineBox* lastLine = nsLineBox::LastLine(mLines); if (lastLine) { lastKid = lastLine->LastChild(); -#ifdef BLOCK_DOES_FIRST_LINE - if (lastLine->IsFirstLine()) { - // Get last frame in the nsFirstLineFrame - lastKid->FirstChild(nsnull, &lastKid); - nsFrameList frames(lastKid); - lastKid = frames.LastChild(); - } -#endif } // Add frames after the last child @@ -4496,50 +4385,16 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, nsLineBox* prevSibLine = nsnull; PRInt32 prevSiblingIndex = -1; if (aPrevSibling) { -#ifdef BLOCK_DOES_FIRST_LINE - // Its possible we have an nsFirstLineFrame managing some of our - // child frames. If we do and the AddFrames is targetted at it, - // use AddFirstLineFrames to get the frames properly placed. - nsIFrame* prevSiblingParent; - aPrevSibling->GetParent(&prevSiblingParent); - if (prevSiblingParent != this) { - // We are attempting an insert into a nsFirstLineFrame. Mark the - // first-line's dirty. Not exactly optimial, but it will - // guarantee a correct reflow. - nsLineBox* line = mLines; - while (line) { - if (!line->IsFirstLine()) { - break; - } - line->MarkDirty(); - line = line->mNext; - } - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)prevSiblingParent, - aFrameList, aPrevSibling); - } - else -#endif - { - // Find the line that contains the previous sibling - prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, - &prevSiblingIndex); - NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); - if (nsnull == prevSibLine) { - // Note: defensive code! FindLineContaining must not return - // null in this case, so if it does... - aPrevSibling = nsnull; - } + // Find the line that contains the previous sibling + prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling, + &prevSiblingIndex); + NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list"); + if (nsnull == prevSibLine) { + // Note: defensive code! FindLineContaining must not return + // null in this case, so if it does... + aPrevSibling = nsnull; } } -#ifdef BLOCK_DOES_FIRST_LINE - else if (mLines && mLines->IsFirstLine()) { - mLines->MarkDirty(); - return AddFirstLineFrames(aPresContext, - (nsFirstLineFrame*)mLines->mFirstChild, - aFrameList, nsnull); - } -#endif // Find the frame following aPrevSibling so that we can join up the // two lists of frames. @@ -4609,151 +4464,12 @@ nsBlockFrame::AddFrames(nsIPresContext* aPresContext, aPrevSibling->SetNextSibling(prevSiblingNextFrame); } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::AddFirstLineFrames(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aFrameList, - nsIFrame* aPrevSibling) -{ - // The first run of inline frames being added always go into the - // line frame. If we hit a block frame then we need to chop the line - // frame into two pieces. - nsIFrame* frame = aFrameList; - nsIFrame* lastAddedFrame = frame; - nsIFrame* firstInlineFrame = nsnull; - PRInt32 pendingInlines = 0; - while (frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - // There are 3 cases. The block is going to the front of the - // line-frames children, in the middle or at the end. - if (aPrevSibling) { - nsIFrame* next; - aPrevSibling->GetNextSibling(&next); - - // Take kids from the line frame starting at next. - nsIFrame* kids; - if (nsnull == next) { - // The block goes in front of aLineFrame's continuation, if - // it has one. - nsFirstLineFrame* nextLineFrame; - aLineFrame->GetNextInFlow((nsIFrame**) &nextLineFrame); - if (!nextLineFrame) { - // No continuation, therefore the block goes after aLineFrame - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, aLineFrame); - } - // Use nextLineFrame and take away all its kids - aLineFrame = nextLineFrame; - } - kids = TakeKidsFromLineFrame(aLineFrame, next); - - // We will leave the line-frame and its continuations in - // place but mark the lines dirty so that they are reflowed - // and the empty line-frames (if any) are cleaned up. - nsLineBox* line = mLines; - nsIFrame* lastLineFrame = aLineFrame; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - lastLineFrame = line->mFirstChild; - line = line->mNext; - } - - // Join the taken kids onto the *end* of the frames being - // added. - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, frame); - return AddFrames(aPresContext, frame, lastLineFrame); - } - else { - // Block is trying to go to the front of the line frame (and - // therefore in front of all the line-frames children and its - // continuations children). Therefore, we don't need a line - // frame anymore. - nsIFrame* kids = TakeKidsFromLineFrame(aLineFrame, nsnull); - - // Join the kids onto the end of the frames being added - nsFrameList newFrames(frame); - newFrames.AppendFrames(this, kids); - FixParentAndView(aPresContext, newFrames.FirstChild()); - - // Remove the line frame (and its continuations). This also - // removes the nsLineBox's that pointed to the line-frame. Do - // this after FixParentAndView because FixParentAndView needs - // a valid old-parent to work. - DoRemoveFrame(aPresContext, aLineFrame); - - // Re-enter AddFrames, this time there won't be any first-line - // frames so we will use the normal path. - return AddFrames(aPresContext, newFrames.FirstChild(), nsnull); - } - } - else { - if (0 == pendingInlines) { - firstInlineFrame = frame; - } - pendingInlines++; - } - lastAddedFrame = frame; - frame->GetNextSibling(&frame); - } - - // All of the frames being added are inline frames - if (pendingInlines) { - return aLineFrame->InsertFrames2(aPresContext, aPrevSibling, aFrameList); - } - return NS_OK; -} - -nsIFrame* -nsBlockFrame::TakeKidsFromLineFrame(nsFirstLineFrame* aLineFrame, - nsIFrame* aFromKid) -{ - nsFrameList kids; - nsIFrame* lastKid; - if (aFromKid) { - kids.SetFrames(aFromKid); - aLineFrame->RemoveFramesFrom(aFromKid); - } - else { - aLineFrame->FirstChild(nsnull, &lastKid); - kids.SetFrames(lastKid); - aLineFrame->RemoveAllFrames(); - } - lastKid = kids.LastChild(); - - // Capture the next-in-flows kids as well. - for (;;) { - aLineFrame->GetNextInFlow((nsIFrame**) &aLineFrame); - if (!aLineFrame) { - break; - } - aLineFrame->FirstChild(nsnull, &aFromKid); - aLineFrame->RemoveAllFrames(); - lastKid->SetNextSibling(aFromKid); - nsFrameList tmp(aFromKid); - lastKid = tmp.LastChild(); - } - - return kids.FirstChild(); -} -#endif void nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame) @@ -4834,15 +4550,6 @@ nsresult nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame) { -#ifdef BLOCK_DOES_FIRST_LINE - nsIFrame* parent; - aDeletedFrame->GetParent(&parent); - if (parent != this) { - return RemoveFirstLineFrame(aPresContext, (nsFirstLineFrame*)parent, - aDeletedFrame); - } -#endif - // Find the line and the previous sibling that contains // deletedFrame; we also find the pointer to the line. nsBlockFrame* flow = this; @@ -4878,9 +4585,7 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, while (nsnull != aDeletedFrame) { while ((nsnull != line) && (nsnull != aDeletedFrame)) { #ifdef NS_DEBUG -#ifndef BLOCK_DOES_FIRST_LINE nsIFrame* parent; -#endif aDeletedFrame->GetParent(&parent); NS_ASSERTION(flow == parent, "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); @@ -4990,60 +4695,12 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext, } } -#ifdef BLOCK_DOES_FIRST_LINE - // Fixup any frames that should be in a first-line frame but aren't - if ((NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) && - (nsnull != mLines) && !mLines->IsBlock()) { - // We just added one or more frame(s) to the first line, or we - // removed a block that preceeded the first line. - WrapFramesInFirstLineFrame(aPresContext); - } -#endif - #ifdef DEBUG VerifyLines(PR_TRUE); #endif return NS_OK; } -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsBlockFrame::RemoveFirstLineFrame(nsIPresContext* aPresContext, - nsFirstLineFrame* aLineFrame, - nsIFrame* aDeletedFrame) -{ - // Strip deleted frame out of the nsFirstLineFrame - aLineFrame->RemoveFrame2(aPresContext, aDeletedFrame); - aDeletedFrame->Destroy(*aPresContext); - - // See if the line-frame and its continuations are now empty - nsFirstLineFrame* lf = (nsFirstLineFrame*) aLineFrame->GetFirstInFlow(); - nsFirstLineFrame* lf0 = lf; - PRBool empty = PR_TRUE; - while (lf) { - nsIFrame* kids; - lf->FirstChild(nsnull, &kids); - if (kids) { - empty = PR_FALSE; - break; - } - lf->GetNextInFlow((nsIFrame**) &lf); - } - if (empty) { - return DoRemoveFrame(aPresContext, lf0); - } - - // Mark first-line lines dirty - nsLineBox* line = mLines; - while (line && line->IsFirstLine()) { - line->MarkDirty(); - line = line->mNext; - } - return NS_OK; -} - -#endif - void nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext& aPresContext, nsIFrame* aChild) @@ -6108,18 +5765,6 @@ nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext) return fls; } -#ifdef BLOCK_DOES_FIRST_LINE -nsIStyleContext* -nsBlockFrame::GetFirstLineStyle(nsIPresContext* aPresContext) -{ - nsIStyleContext* fls; - aPresContext->ProbePseudoStyleContextFor(mContent, - nsHTMLAtoms::firstLinePseudo, - mStyleContext, PR_FALSE, &fls); - return fls; -} -#endif - NS_IMETHODIMP nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, nsIAtom* aListName, @@ -6143,18 +5788,6 @@ nsBlockFrame::SetInitialChildList(nsIPresContext& aPresContext, #endif NS_RELEASE(firstLetterStyle); } - -#ifdef BLOCK_DOES_FIRST_LINE - nsIStyleContext* firstLineStyle = GetFirstLineStyle(&aPresContext); - if (nsnull != firstLineStyle) { - mState |= NS_BLOCK_HAS_FIRST_LINE_STYLE; -#ifdef NOISY_FIRST_LINE - ListTag(stdout); - printf(": first-line style found\n"); -#endif - NS_RELEASE(firstLineStyle); - } -#endif } rv = AddFrames(&aPresContext, aChildList, nsnull); @@ -6448,15 +6081,7 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) nsIFrame* frame = line->mFirstChild; PRInt32 n = line->GetChildCount(); while (--n >= 0) { - nsresult rv = frame->FindTextRuns(textRunThingy); - if (NS_OK != rv) { - return rv; - } - else { - // A frame that doesn't implement nsIHTMLReflow isn't text - // therefore it will end an open text run. - textRunThingy.EndTextRun(); - } + frame->FindTextRuns(textRunThingy); frame->GetNextSibling(&frame); } } @@ -6474,210 +6099,6 @@ nsBlockFrame::ComputeTextRuns(nsIPresContext* aPresContext) return NS_OK; } -//---------------------------------------------------------------------- - -nsresult -NS_NewAnonymousBlockFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsAnonymousBlockFrame* it = new nsAnonymousBlockFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsAnonymousBlockFrame::nsAnonymousBlockFrame() -{ -} - -nsAnonymousBlockFrame::~nsAnonymousBlockFrame() -{ -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -} - -NS_IMETHODIMP -nsAnonymousBlockFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -} - -nsresult -nsAnonymousBlockFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::AppendFrames(*aPresContext, *aPresShell, - aListName, aFrameList); -} - -nsresult -nsAnonymousBlockFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - return nsAnonymousBlockFrameSuper::InsertFrames(*aPresContext, *aPresShell, - aListName, aPrevFrame, - aFrameList); -} - -nsresult -nsAnonymousBlockFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIPresShell* aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - return nsAnonymousBlockFrameSuper::RemoveFrame(*aPresContext, *aPresShell, - aListName, aOldFrame); -} - -void -nsAnonymousBlockFrame::RemoveFirstFrame() -{ - nsLineBox* line = mLines; - if (nsnull != line) { - nsIFrame* firstChild = line->mFirstChild; - -#if XXX - // If the line has floaters on it, see if the frame being removed - // is a placeholder frame. If it is, then remove it from the lines - // floater array and from the block frames floater child list. - if (line->mFloaters.NotEmpty()) { - // XXX UNTESTED! - nsPlaceholderFrame* placeholderFrame; - nsVoidArray& floaters = *line->mFloaters; - PRInt32 i, n = floaters.Count(); - for (i = 0; i < n; i++) { - placeholderFrame = (nsPlaceholderFrame*) floaters[i]; - if (firstChild == placeholderFrame) { - // Remove placeholder from the line's floater array - floaters.RemoveElementAt(i); - if (0 == floaters.Count()) { - delete line->mFloaters; - line->mFloaters = nsnull; - } - - // Remove the floater from the block frames mFloaters list too - mFloaters.RemoveFrame(placeholderFrame->GetOutOfFlowFrame()); - break; - } - } - } -#endif - - PRInt32 lineChildCount = line->GetChildCount(); - if (1 == lineChildCount) { - // Remove line when last frame goes away - mLines = line->mNext; - delete line; - } - else { - // Remove frame from line and mark the line dirty - line->SetChildCount(lineChildCount - 1); - line->MarkDirty(); - firstChild->GetNextSibling(&line->mFirstChild); - } - - // Break linkage to next child after stolen frame - firstChild->SetNextSibling(nsnull); - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - -void -nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame) -{ - nsLineBox* line = mLines; - if (nsnull != line) { - // Chop the child sibling list into two pieces - nsFrameList tmp(line->mFirstChild); - nsIFrame* prevSibling = tmp.GetPrevSiblingFor(aFrame); - if (nsnull != prevSibling) { - // Chop the sibling list into two pieces - prevSibling->SetNextSibling(nsnull); - - nsLineBox* prevLine = nsnull; - while (nsnull != line) { - nsIFrame* frame = line->mFirstChild; - PRInt32 i, n = line->GetChildCount(); - PRBool done = PR_FALSE; - for (i = 0; i < n; i++) { - if (frame == aFrame) { - // We just found the target frame (and the line its in and - // the previous line) - if (frame == line->mFirstChild) { - // No more children on this line, so let it get removed - prevLine->mNext = nsnull; - } - else { - // The only frames that remain on this line are the - // frames preceeding aFrame. Adjust the count to - // indicate that fact. - line->SetChildCount(i); - - // Remove the lines that follow this line - prevLine = line; - line = line->mNext; - prevLine->mNext = nsnull; - } - done = PR_TRUE; - break; - } - frame->GetNextSibling(&frame); - } - if (done) { - break; - } - prevLine = line; - line = line->mNext; - } - } - - // Remove all of the remaining lines - while (nsnull != line) { - nsLineBox* next = line->mNext; - delete line; - line = next; - } - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif -} - #ifdef DEBUG void nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) @@ -6700,24 +6121,9 @@ nsBlockFrame::VerifyLines(PRBool aFinalCheckOK) if (line->IsBlock()) { seenBlock = PR_TRUE; } -#ifdef BLOCK_DOES_FIRST_LINE - if (line->IsFirstLine()) { - NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); - } -#endif if (line->IsBlock()) { NS_ASSERTION(1 == line->GetChildCount(), "bad first line"); } -#ifdef BLOCK_DOES_FIRST_LINE - if (NS_BLOCK_HAS_FIRST_LINE_STYLE & mState) { - if (seenBlock) { - NS_ASSERTION(!line->IsFirstLine(), "bad first line"); - } - else { - NS_ASSERTION(line->IsFirstLine(), "bad first line"); - } - } -#endif } count += line->GetChildCount(); line = line->mNext; diff --git a/layout/html/base/src/nsInlineFrame.cpp b/layout/html/base/src/nsInlineFrame.cpp index 6b1a04b6719f..9df8320eb064 100644 --- a/layout/html/base/src/nsInlineFrame.cpp +++ b/layout/html/base/src/nsInlineFrame.cpp @@ -16,13 +16,11 @@ * Corporation. Portions created by Netscape are Copyright (C) 1998 * Netscape Communications Corporation. All Rights Reserved. */ +#include "nsCOMPtr.h" #include "nsInlineFrame.h" -#include "nsBlockFrame.h" -#include "nsBlockReflowContext.h" #include "nsHTMLIIDs.h" #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" -#include "nsCOMPtr.h" #include "nsIStyleContext.h" #include "nsIPresShell.h" #include "nsIPresContext.h" @@ -31,24 +29,804 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLayoutAtoms.h" -// XXX TODO: -// append/insert/remove floater testing - -// Theory of operation: -// XXX write this - -#ifdef DEBUG -#undef NOISY_ANON_BLOCK -#undef NOISY_REFLOW_REASON -#else -#undef NOISY_ANON_BLOCK -#undef NOISY_REFLOW_REASON -#endif +#define NOISY_FINAL_SIZE nsIID nsInlineFrame::kInlineFrameCID = NS_INLINE_FRAME_CID; ////////////////////////////////////////////////////////////////////// +// Basic nsInlineFrame methods + +nsresult +NS_NewInlineFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsInlineFrame* it = new nsInlineFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsInlineFrame::nsInlineFrame() +{ +} + +NS_IMETHODIMP +nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kInlineFrameCID)) { + nsInlineFrame* tmp = this; + *aInstancePtr = (void*) tmp; + return NS_OK; + } + return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr); +} + +NS_IMETHODIMP +nsInlineFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Inline", aResult); +} + +NS_IMETHODIMP +nsInlineFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::inlineFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aFrameList) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (aFrameList) { + mFrames.AppendFrames(this, aFrameList); + + // generate a reflow command for this frame + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::InsertFrames(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (aFrameList) { + // Insert frames after aPrevFrame + mFrames.InsertFrames(this, aPrevFrame, aFrameList); + + // generate a reflow command for this frame + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::RemoveFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + + if (aOldFrame) { + // Loop and destroy the frame and all of its continuations. + PRBool generateReflowCommand = PR_FALSE; + nsIFrame* oldFrameParent; + aOldFrame->GetParent(&oldFrameParent); + nsInlineFrame* parent = (nsInlineFrame*) oldFrameParent; + while (nsnull != aOldFrame) { + // If the frame being removed has zero size then don't bother + // generating a reflow command, otherwise make sure we do. + nsRect bbox; + aOldFrame->GetRect(bbox); + if (bbox.width || bbox.height) { + generateReflowCommand = PR_TRUE; + } + + // When the parent is an inline frame we have a simple task - just + // remove the frame from its parents list and generate a reflow + // command. + nsIFrame* oldFrameNextInFlow; + aOldFrame->GetNextInFlow(&oldFrameNextInFlow); + nsSplittableType st; + aOldFrame->IsSplittable(st); + if (NS_FRAME_NOT_SPLITTABLE != st) { + nsSplittableFrame::RemoveFromFlow(aOldFrame); + } + parent->mFrames.DestroyFrame(aPresContext, aOldFrame); + aOldFrame = oldFrameNextInFlow; + if (nsnull != aOldFrame) { + aOldFrame->GetParent((nsIFrame**) &parent); + } + } + + if (generateReflowCommand) { + // generate a reflow command for "this" + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsInlineFrame::ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame) +{ + if (nsnull != aListName) { + return NS_ERROR_INVALID_ARG; + } + if (!aOldFrame || !aNewFrame) { + return NS_ERROR_INVALID_ARG; + } + + // Replace the old frame with the new frame in the list, then remove the old frame + mFrames.ReplaceFrame(this, aOldFrame, aNewFrame); + aOldFrame->Destroy(aPresContext); + + // generate a reflow command for "this" + nsCOMPtr reflowCmd; + NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), this, nsIReflowCommand::ReflowDirty); + if (reflowCmd) { + aPresShell.AppendReflowCommand(reflowCmd); + } + + return NS_OK; +} + +////////////////////////////////////////////////////////////////////// +// Reflow methods + +NS_IMETHODIMP +nsInlineFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + if (nsnull == aReflowState.mLineLayout) { + return NS_ERROR_INVALID_ARG; + } + DrainOverflow(&aPresContext); + + if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { +#ifdef DEBUG_kipp + { + extern char* nsPresShell_ReflowStackPointerTop; + char marker; + char* newsp = (char*) ▮ + printf("XXX: frame tree is too deep; approx stack size = %d\n", + nsPresShell_ReflowStackPointerTop - newsp); + } +#endif + aStatus = NS_FRAME_COMPLETE; + return NS_OK; + } + + // Set our own reflow state (additional state above and beyond + // aReflowState) + InlineReflowState irs; + irs.mPrevFrame = nsnull; + irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; + irs.mNextRCFrame = nsnull; + if (eReflowReason_Incremental == aReflowState.reason) { + // Peel off the next frame in the path if this is an incremental + // reflow aimed at one of the children. + nsIFrame* target; + aReflowState.reflowCommand->GetTarget(target); + if (this != target) { + aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); + } + } + + nsresult rv; + if (mFrames.IsEmpty()) { + // Try to pull over one frame before starting so that we know + // whether we have an anonymous block or not. + PRBool complete; + (void) PullOneFrame(&aPresContext, irs, &complete); + } + + rv = ReflowFrames(&aPresContext, aReflowState, irs, aMetrics, aStatus); + + // Note: the line layout code will properly compute our + // NS_FRAME_OUTSIDE_CHILDREN state for us. + + return rv; +} + +NS_IMETHODIMP +nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) +{ + nsIFrame* frame = mFrames.FirstChild(); + while (nsnull != frame) { + frame->FindTextRuns(aLineLayout); + frame->GetNextSibling(&frame); + } + return NS_OK; +} + +void +nsInlineFrame::DrainOverflow(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); + + if (prevOverflowFrames) { + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + for (nsIFrame* f = prevOverflowFrames; f; f->GetNextSibling(&f)) { + nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevInFlow, this); + } + mFrames.InsertFrames(this, nsnull, prevOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); + if (overflowFrames) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + mFrames.AppendFrames(nsnull, overflowFrames); + } +} + +nsresult +nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& irs, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus) +{ + nsresult rv = NS_OK; + aStatus = NS_FRAME_COMPLETE; + + nsLineLayout* lineLayout = aReflowState.mLineLayout; + nscoord leftEdge = 0; + if (nsnull == mPrevInFlow) { + leftEdge = aReflowState.mComputedBorderPadding.left; + } + nscoord availableWidth = aReflowState.availableWidth; + if (NS_UNCONSTRAINEDSIZE != availableWidth) { + // Subtract off left and right border+padding from availableWidth + availableWidth -= leftEdge; + availableWidth -= aReflowState.mComputedBorderPadding.right; + } + lineLayout->BeginSpan(this, &aReflowState, leftEdge, leftEdge + availableWidth); + + // First reflow our current children + nsIFrame* frame = mFrames.FirstChild(); + PRBool done = PR_FALSE; + while (nsnull != frame) { + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); + if (NS_FAILED(rv)) { + done = PR_TRUE; + break; + } + if (NS_FRAME_COMPLETE != aStatus) { + if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { + done = PR_TRUE; + break; + } + } + irs.mPrevFrame = frame; + frame->GetNextSibling(&frame); + } + + // Attempt to pull frames from our next-in-flow until we can't + if (!done && (nsnull != mNextInFlow)) { + while (!done) { + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + PRBool isComplete; + frame = PullOneFrame(aPresContext, irs, &isComplete); + if (nsnull == frame) { + if (!isComplete) { + aStatus = NS_FRAME_NOT_COMPLETE; + } + break; + } + rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); + if (NS_FAILED(rv)) { + done = PR_TRUE; + break; + } + if (NS_FRAME_COMPLETE != aStatus) { + if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { + done = PR_TRUE; + break; + } + } + irs.mPrevFrame = frame; + } + } +#ifdef DEBUG + if (NS_FRAME_COMPLETE == aStatus) { + // We can't be complete AND have overflow frames! + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE); + NS_ASSERTION(!overflowFrames, "whoops"); + } +#endif + + // If after reflowing our children they take up no area then make + // sure that we don't either. + // + // Note: CSS demands that empty inline elements still affect the + // line-height calculations. However, continuations of an inline + // that are empty we force to empty so that things like collapsed + // whitespace in an inline element don't affect the line-height. + nsSize size; + lineLayout->EndSpan(this, size, aMetrics.maxElementSize); + if ((0 == size.height) && (0 == size.width) && + ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { + // This is a continuation of a previous inline. Therefore make + // sure we don't affect the line-height. + aMetrics.width = 0; + aMetrics.height = 0; + aMetrics.ascent = 0; + aMetrics.descent = 0; + if (nsnull != aMetrics.maxElementSize) { + aMetrics.maxElementSize->width = 0; + aMetrics.maxElementSize->height = 0; + } + } + else { + // Compute final width + aMetrics.width = size.width; + if (nsnull == mPrevInFlow) { + aMetrics.width += aReflowState.mComputedBorderPadding.left; + } + if (NS_FRAME_IS_COMPLETE(aStatus)) { + aMetrics.width += aReflowState.mComputedBorderPadding.right; + } + + const nsStyleFont* font; + GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); + aReflowState.rendContext->SetFont(font->mFont); + nsCOMPtr fm; + aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); + + // Compute final height of the frame. + // + // Do things the standard css2 way -- though it's hard to find it + // in the css2 spec! It's actually found in the css1 spec section + // 4.4 (you will have to read between the lines to really see + // it). + // + // The height of our box is the sum of our font size plus the top + // and bottom border and padding. The height of children do not + // affect our height. + fm->GetMaxAscent(aMetrics.ascent); + fm->GetMaxDescent(aMetrics.descent); + fm->GetHeight(aMetrics.height); + aMetrics.ascent += aReflowState.mComputedBorderPadding.top; + aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; + aMetrics.height += aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; + + // Note: we normally use the actual font height for computing the + // line-height raw value from the style context. On systems where + // they disagree the actual font height is more appropriate. This + // little hack lets us override that behavior to allow for more + // precise layout in the face of imprecise fonts. + if (nsHTMLReflowState::UseComputedHeight()) { + aMetrics.height = font->mFont.size + + aReflowState.mComputedBorderPadding.top + + aReflowState.mComputedBorderPadding.bottom; + } + } + + // For now our combined area is zero. The real value will be + // computed during vertical alignment of the line we are on. + aMetrics.mCombinedArea.x = 0; + aMetrics.mCombinedArea.y = 0; + aMetrics.mCombinedArea.width = aMetrics.width; + aMetrics.mCombinedArea.height = aMetrics.height; + +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": metrics=%d,%d ascent=%d descent=%d\n", + aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); +#endif + + return rv; +} + +nsresult +nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& irs, + nsIFrame* aFrame, + nsReflowStatus& aStatus) +{ + nsLineLayout* lineLayout = aReflowState.mLineLayout; + PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); + nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); + if (NS_FAILED(rv)) { + return rv; + } + if (NS_INLINE_IS_BREAK(aStatus)) { + if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { + if (aFrame != mFrames.FirstChild()) { + // Change break-before status into break-after since we have + // already placed at least one child frame. This preserves the + // break-type so that it can be propogated upward. + aStatus = NS_FRAME_NOT_COMPLETE | + NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | + (aStatus & NS_INLINE_BREAK_TYPE_MASK); + PushFrames(aPresContext, aFrame, irs.mPrevFrame); + } + else { + // Preserve reflow status when breaking-before our first child + // and propogate it upward without modification. + } + } + else { + // Break-after + if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + nsIFrame* newFrame; + rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); + if (NS_FAILED(rv)) { + return rv; + } + } + nsIFrame* nextFrame; + aFrame->GetNextSibling(&nextFrame); + if (nsnull != nextFrame) { + aStatus |= NS_FRAME_NOT_COMPLETE; + PushFrames(aPresContext, nextFrame, aFrame); + } + else if (nsnull != mNextInFlow) { + // We must return an incomplete status if there are more child + // frames remaining in a next-in-flow that follows this frame. + nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; + while (nsnull != nextInFlow) { + if (nextInFlow->mFrames.NotEmpty()) { + aStatus |= NS_FRAME_NOT_COMPLETE; + break; + } + nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; + } + } + } + } + else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { + nsIFrame* newFrame; + rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); + if (NS_FAILED(rv)) { + return rv; + } + if (!reflowingFirstLetter) { + nsIFrame* nextFrame; + aFrame->GetNextSibling(&nextFrame); + if (nsnull != nextFrame) { + PushFrames(aPresContext, nextFrame, aFrame); + } + } + } + return rv; +} + +nsIFrame* +nsInlineFrame::PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& irs, + PRBool* aIsComplete) +{ + PRBool isComplete = PR_TRUE; + + nsIFrame* frame = nsnull; + nsInlineFrame* nextInFlow = irs.mNextInFlow; + while (nsnull != nextInFlow) { + frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); + if (nsnull != frame) { + isComplete = PR_FALSE; + nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); + break; + } + nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; + irs.mNextInFlow = nextInFlow; + } + + *aIsComplete = isComplete; + return frame; +} + +void +nsInlineFrame::PushFrames(nsIPresContext* aPresContext, + nsIFrame* aFromChild, + nsIFrame* aPrevSibling) +{ + NS_PRECONDITION(nsnull != aFromChild, "null pointer"); + NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); +#ifdef DEBUG + nsIFrame* prevNextSibling; + aPrevSibling->GetNextSibling(&prevNextSibling); + NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); +#endif + + // Disconnect aFromChild from its previous sibling + aPrevSibling->SetNextSibling(nsnull); + + // Add the frames to our overflow list (let our next in flow drain + // our overflow list when it is ready) + SetOverflowFrames(aPresContext, aFromChild); +} + +////////////////////////////////////////////////////////////////////// + +PRIntn +nsInlineFrame::GetSkipSides() const +{ + PRIntn skip = 0; + if (nsnull != mPrevInFlow) { + nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow; + if (prev->mRect.height || prev->mRect.width) { + // Prev-in-flow is not empty therefore we don't render our left + // border edge. + skip |= 1 << NS_SIDE_LEFT; + } + else { + // If the prev-in-flow is empty, then go ahead and let our right + // edge border render. + } + } + if (nsnull != mNextInFlow) { + nsInlineFrame* next = (nsInlineFrame*) mNextInFlow; + if (next->mRect.height || next->mRect.width) { + // Next-in-flow is not empty therefore we don't render our right + // border edge. + skip |= 1 << NS_SIDE_RIGHT; + } + else { + // If the next-in-flow is empty, then go ahead and let our right + // edge border render. + } + } + return skip; +} + +////////////////////////////////////////////////////////////////////// + +// nsLineFrame implementation + +static void +ReParentChildListStyle(nsIPresContext* aPresContext, + nsIStyleContext* aParentStyleContext, + nsFrameList& aFrameList) +{ + nsIFrame* kid = aFrameList.FirstChild(); + while (nsnull != kid) { + aPresContext->ReParentStyleContext(kid, aParentStyleContext); + kid->GetNextSibling(&kid); + } +} + +nsresult +NS_NewFirstLineFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsInlineFrame* it = new nsFirstLineFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsFirstLineFrame::nsFirstLineFrame() +{ +} + +NS_IMETHODIMP +nsFirstLineFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Line", aResult); +} + +NS_IMETHODIMP +nsFirstLineFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::lineFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +void +nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame) +{ + nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame); + if (prevFrame) { + prevFrame->SetNextSibling(nsnull); + } + else { + mFrames.SetFrames(nsnull); + } +} + +nsIFrame* +nsFirstLineFrame::PullOneFrame(nsIPresContext* aPresContext, InlineReflowState& irs, PRBool* aIsComplete) +{ + nsIFrame* frame = nsInlineFrame::PullOneFrame(aPresContext, irs, aIsComplete); + if (frame && !mPrevInFlow) { + // We are a first-line frame. Fixup the child frames + // style-context that we just pulled. + aPresContext->ReParentStyleContext(frame, mStyleContext); + } + return frame; +} + +void +nsFirstLineFrame::DrainOverflow(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); + if (prevOverflowFrames) { + nsFrameList frames(prevOverflowFrames); + + ReParentChildListStyle(aPresContext, mStyleContext, frames); + mFrames.InsertFrames(this, nsnull, prevOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); + if (overflowFrames) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + nsFrameList frames(overflowFrames); + + ReParentChildListStyle(aPresContext, mStyleContext, frames); + mFrames.AppendFrames(nsnull, overflowFrames); + } +} + +NS_IMETHODIMP +nsFirstLineFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + if (nsnull == aReflowState.mLineLayout) { + return NS_ERROR_INVALID_ARG; + } + DrainOverflow(&aPresContext); + + // Set our own reflow state (additional state above and beyond + // aReflowState) + InlineReflowState irs; + irs.mPrevFrame = nsnull; + irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; + irs.mNextRCFrame = nsnull; + if (eReflowReason_Incremental == aReflowState.reason) { + // Peel off the next frame in the path if this is an incremental + // reflow aimed at one of the children. + nsIFrame* target; + aReflowState.reflowCommand->GetTarget(target); + if (this != target) { + aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); + } + } + + nsresult rv; + PRBool wasEmpty = mFrames.IsEmpty(); + if (wasEmpty) { + // Try to pull over one frame before starting so that we know + // whether we have an anonymous block or not. + PRBool complete; + PullOneFrame(&aPresContext, irs, &complete); + } + + if (nsnull == mPrevInFlow) { + // XXX This is pretty sick, but what we do here is to pull-up, in + // advance, all of the next-in-flows children. We re-resolve their + // style while we are at at it so that when we reflow they have + // the right style. + // + // All of this is so that text-runs reflow properly. + irs.mPrevFrame = mFrames.LastChild(); + for (;;) { + PRBool complete; + nsIFrame* frame = PullOneFrame(&aPresContext, irs, &complete); + if (!frame) { + break; + } + irs.mPrevFrame = frame; + } + irs.mPrevFrame = nsnull; + } + else { +// XXX do this in the Init method instead + // For continuations, we need to check and see if our style + // context is right. If its the same as the first-in-flow, then + // we need to fix it up (that way :first-line style doesn't leak + // into this continuation since we aren't the first line). + nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow(); + if (mStyleContext == first->mStyleContext) { + // Fixup our style context and our children. First get the + // proper parent context. + nsIFrame* parentFrame; + first->GetParent(&parentFrame); + nsIStyleContext* parentContext; + parentFrame->GetStyleContext(&parentContext); + if (parentContext) { + // Create a new style context that is a child of the parent + // style context thus removing the :first-line style. This way + // we behave as if an anonymous (unstyled) span was the child + // of the parent frame. + nsIStyleContext* newSC; + aPresContext.ResolvePseudoStyleContextFor(mContent, + nsHTMLAtoms::mozLineFrame, + parentContext, + PR_FALSE, &newSC); + if (newSC) { + // Switch to the new style context. + SetStyleContext(&aPresContext, newSC); + + // Re-resolve all children + ReParentChildListStyle(&aPresContext, mStyleContext, mFrames); + + NS_RELEASE(newSC); + } + NS_RELEASE(parentContext); + } + } + } + + rv = ReflowFrames(&aPresContext, aReflowState, irs, aMetrics, aStatus); + + // Note: the line layout code will properly compute our + // NS_FRAME_OUTSIDE_CHILDREN state for us. + + return rv; +} + +////////////////////////////////////////////////////////////////////// + nsresult NS_NewPositionedInlineFrame(nsIFrame** aNewFrame) { @@ -224,1950 +1002,9 @@ nsPositionedInlineFrame::Reflow(nsIPresContext& aPresContext, return rv; } -////////////////////////////////////////////////////////////////////// - -// SectionData implementation - -nsInlineFrame::SectionData::SectionData(nsIFrame* aFrameList) -{ - firstBlock = nsnull; - prevFirstBlock = nsnull; - lastBlock = nsnull; - lastFrame = nsnull; - - // Find the first and last block (if any!). When we exit the loop - // lastFrame will be the last frame in aList. - nsIFrame* frame = aFrameList; - firstFrame = aFrameList; - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - if (nsnull == firstBlock) { - prevFirstBlock = lastFrame; - firstBlock = frame; - lastBlock = frame; - } - else { - lastBlock = frame; - } - } - lastFrame = frame; - frame->GetNextSibling(&frame); - } -} - -PRBool -nsInlineFrame::SectionData::SplitFrameList(nsFrameList& aSection1, - nsFrameList& aSection2, - nsFrameList& aSection3) -{ - if (nsnull == firstBlock) { - // There are no blocks - return PR_FALSE; - } - - // We have at least one block - if (nsnull != prevFirstBlock) { - // The first block is not the first frame in aList. Setup section1. - prevFirstBlock->SetNextSibling(nsnull); - aSection1.SetFrames(firstFrame); - } - aSection2.SetFrames(firstBlock); - - if (lastFrame != lastBlock) { - // There are inline frames that follow the last block. Setup section3. - nsIFrame* nextSib; - lastBlock->GetNextSibling(&nextSib); - lastBlock->SetNextSibling(nsnull); - aSection3.SetFrames(nextSib); - } - - return PR_TRUE; -} - -//////////////////////////////////////////////////////////////////////// -// Basic nsInlineFrame methods - -nsresult -NS_NewInlineFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(aNewFrame, "null OUT ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsInlineFrame* it = new nsInlineFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsInlineFrame::nsInlineFrame() -{ -} - -NS_IMETHODIMP -nsInlineFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) -{ - if (nsnull == aInstancePtr) { - return NS_ERROR_NULL_POINTER; - } - if (aIID.Equals(kInlineFrameCID)) { - nsInlineFrame* tmp = this; - *aInstancePtr = (void*) tmp; - return NS_OK; - } - return nsInlineFrameSuper::QueryInterface(aIID, aInstancePtr); -} - -NS_IMETHODIMP -nsInlineFrame::GetFrameName(nsString& aResult) const -{ - return MakeFrameName("Inline", aResult); -} - -NS_IMETHODIMP -nsInlineFrame::GetFrameType(nsIAtom** aType) const -{ - NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); - *aType = nsLayoutAtoms::inlineFrame; - NS_ADDREF(*aType); - return NS_OK; -} - -NS_IMETHODIMP -nsInlineFrame::Destroy(nsIPresContext& aPresContext) -{ - mFrames.DestroyFrames(aPresContext); - return nsInlineFrameSuper::Destroy(aPresContext); -} - -////////////////////////////////////////////////////////////////////// -// nsInlineFrame child management - -// Find the first inline frame, looking backwards starting at "this", -// that contains an anonymous block. Return nsnull if an anonymous -// block is not found. -nsAnonymousBlockFrame* -nsInlineFrame::FindPrevAnonymousBlock(nsInlineFrame** aBlockParent) -{ - nsInlineFrame* prevInFlow = this; - while (nsnull != prevInFlow) { - // Scan the prev-in-flows frame list, looking for an anonymous - // block frame. - nsIFrame* frame = prevInFlow->mFrames.FirstChild(); - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - *aBlockParent = prevInFlow; - return (nsAnonymousBlockFrame*) frame; - } - frame->GetNextSibling(&frame); - } - prevInFlow = (nsInlineFrame*) prevInFlow->mPrevInFlow; - } - return nsnull; -} - -// Find the first inline frame, looking forwards starting at "this", -// that contains an anonymous block. Return nsnull if an anonymous -// block is not found. -nsAnonymousBlockFrame* -nsInlineFrame::FindAnonymousBlock(nsInlineFrame** aBlockParent) -{ - nsInlineFrame* nextInFlow = this; - while (nsnull != nextInFlow) { - // Scan the prev-in-flows frame list, looking for an anonymous - // block frame. - nsIFrame* frame = nextInFlow->mFrames.FirstChild(); - while (nsnull != frame) { - if (nsLineLayout::TreatFrameAsBlock(frame)) { - *aBlockParent = nextInFlow; - return (nsAnonymousBlockFrame*) frame; - } - frame->GetNextSibling(&frame); - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - return nsnull; -} - -nsresult -nsInlineFrame::CreateAnonymousBlock(nsIPresContext& aPresContext, - nsIFrame* aInitialFrames, - nsIFrame** aResult) -{ - nsIFrame* bf; - nsresult rv = NS_NewAnonymousBlockFrame(&bf); - if (NS_SUCCEEDED(rv)) { - nsCOMPtr newSC; - aPresContext.ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozAnonymousBlock, - mStyleContext, - PR_FALSE, - getter_AddRefs(newSC)); - rv = bf->Init(aPresContext, mContent, this, newSC, nsnull); - if (NS_FAILED(rv)) { - bf->Destroy(aPresContext); - delete bf; - } - else { - // Set parent for the frames now that the anonymous block has - // been created. - nsIFrame* frame = aInitialFrames; - while (nsnull != frame) { - frame->SetParent(bf); - frame->GetNextSibling(&frame); - } - rv = bf->SetInitialChildList(aPresContext, nsnull, aInitialFrames); - } - *aResult = bf; - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::SetInitialChildList(nsIPresContext& aPresContext, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_UNEXPECTED; - } - if (nsnull == aFrameList) { - return NS_OK; - } - nsCOMPtr shell; - nsresult rv = aPresContext.GetShell(getter_AddRefs(shell)); - if (NS_SUCCEEDED(rv) && shell) { - rv = AppendFrames(aPresContext, *shell, aFrameList, PR_FALSE); - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - if (nsnull == aFrameList) { - return NS_OK; - } - return AppendFrames(aPresContext, aPresShell, aFrameList, PR_TRUE); -} - -nsresult -nsInlineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aFrameList, - PRBool aGenerateReflowCommands) -{ -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": append "); - nsFrame::ListTag(stdout, aFrameList); - nsIFrame* lastKid = mFrames.LastChild(); - if (lastKid) { - printf(" after "); - nsFrame::ListTag(stdout, lastKid); - } - printf("\n"); -#endif - - nsresult rv = NS_OK; - SectionData sd(aFrameList); - if (sd.HasABlock()) { - nsFrameList section1, section2, section3; - sd.SplitFrameList(section1, section2, section3); - - // There is at least one block in the new frames. See if there is - // an anonymous block frame in a prev-in-flow of this frame. - nsInlineFrame* prevInline; - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = FindPrevAnonymousBlock(&prevInline); - if (nsnull != anonymousBlock) { - // One of the invariants of nsInlineFrame is that there will be - // at most one anonymous block frame that reflows the - // nsInlineFrame's block children (not counting any - // continuations of the anonymous block frame). - // - // We maintain that invariant by noticing when a new block frame - // enters the list of children and ensuring that all of the - // frames from the first block to the last block are contained - // by the anonymous block (or one of its continuations). This - // can cause some inline frames between here and the inline that - // contains anonymousBlock to have their children stuffed into - // the anonymous block. - - // Build a list of the frames between the anonymous block and - // this frame, stealing children from our continuation frames as - // necessary. - nsIFrame* inlineSiblings; - anonymousBlock->GetNextSibling(&inlineSiblings); - nsFrameList newBlockFrames; - if (nsnull != inlineSiblings) { - newBlockFrames.AppendFrames(anonymousBlock, inlineSiblings); - } - nsInlineFrame* tmp = (nsInlineFrame*) prevInline->mNextInFlow; - while ((nsnull != tmp) && (this != tmp)) { - newBlockFrames.AppendFrames(anonymousBlock, tmp->mFrames); - tmp = (nsInlineFrame*) tmp->mNextInFlow; - } - - // Now tack on all of this frame's child frames (unless this - // frame is the frame that contains the anonymous block) - if (this != prevInline) { - newBlockFrames.AppendFrames(anonymousBlock, mFrames); - } - - // And then append section1 and section2 frames. - if (section1.NotEmpty()) { - newBlockFrames.AppendFrames(anonymousBlock, section1); - } - newBlockFrames.AppendFrames(anonymousBlock, section2); - - // Finally, if there are any frames in section3 then they are - // appended after the anonymous block. These frames will be - // reflowed when they are pushed from the prevInline frame to a - // next-in-flow after the anonymousBlock frame is reflowed. - anonymousBlock->SetNextSibling(section3.FirstChild()); - - // Now we can append the frames to the anonymous block and it - // can generate a reflow command. - rv = anonymousBlock->AppendFrames2(&aPresContext, &aPresShell, nsnull, - newBlockFrames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 1\n"); -#endif - } - else { - // There is no prior block frames that are the children of this - // inline. Therefore, section 1 is appended to our frame list - // and we wrap up the frames in section 2 with a new anonymous - // block and the frames in section 3 get appended to the frame - // list after the anonymous frame (so that they can be pushed to - // a next-in-flow after this finishes reflowing its anonymous - // block). - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, section2.FirstChild(), - &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - if (section1.NotEmpty()) { - mFrames.AppendFrames(nsnull, section1); - } - mFrames.AppendFrame(nsnull, anonBlock); - if (section3.NotEmpty()) { - mFrames.AppendFrames(nsnull, section3); - } -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 2\n"); -#endif - - if (aGenerateReflowCommands) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - } - } - else { - // The new frames contain no block frames - mFrames.AppendFrames(this, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("AppendFrames: case 3\n"); -#endif - - if (aGenerateReflowCommands) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, this, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - } - - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - if (nsnull == aFrameList) { - return NS_OK; - } - -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": insert "); - nsFrame::ListTag(stdout, aFrameList); - if (aPrevFrame) { - printf(" after "); - nsFrame::ListTag(stdout, aPrevFrame); - } - printf("\n"); -#endif - - nsresult rv = NS_OK; - SectionData sd(aFrameList); - if (sd.HasABlock()) { - // Break insertion up into 3 pieces - nsFrameList section1, section2, section3; - sd.SplitFrameList(section1, section2, section3); - - nsIFrame* prevFrame = aPrevFrame; - - // First insert the inlines in section1 after prevFrame - if (section1.NotEmpty()) { - nsIFrame* newPrevFrame = section1.LastChild(); - rv = InsertInlineFrames(aPresContext, aPresShell, prevFrame, - section1.FirstChild()); - prevFrame = newPrevFrame; - } - - // Next insert the frames in section2 after prevFrame - if (NS_SUCCEEDED(rv)) { - nsIFrame* newPrevFrame = section2.LastChild(); - rv = InsertBlockFrames(aPresContext, aPresShell, prevFrame, - section2.FirstChild()); - prevFrame = newPrevFrame; - } - - // Finally, insert the frames in section3 after prevFrame - if (NS_SUCCEEDED(rv) && section3.NotEmpty()) { - rv = InsertInlineFrames(aPresContext, aPresShell, prevFrame, - section3.FirstChild()); - } - } - else { - // Use simpler path when the insertion is only inline frames - rv = InsertInlineFrames(aPresContext, aPresShell, aPrevFrame, aFrameList); - } - - return rv; -} - -nsresult -nsInlineFrame::InsertBlockFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - if (nsnull == aPrevFrame) { - // The block is being inserted at the head of all the child - // frames. - nsInlineFrame* flow; - nsAnonymousBlockFrame* anonymousBlock = FindAnonymousBlock(&flow); - if (nsnull == anonymousBlock) { - // There are no anonymous blocks so create one and place the - // frames into it. - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, aFrameList, &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - mFrames.InsertFrames(this, nsnull, anonBlock); - target = this; - generateReflowCommand = PR_TRUE; -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 1\n"); -#endif - } - else { - // Take all of the frames before the anonymous block, plus the - // frames in aFrameList and insert them into the anonymous - // block. - nsFrameList frames; - frames.AppendFrames(anonymousBlock, aFrameList); - nsInlineFrame* start = this; - while (start != flow) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - nsnull, frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 2\n"); -#endif - } - } - else { - // First see if the insertion is inside the anonymous block - nsIFrame* prevFrameParent; - aPrevFrame->GetParent(&prevFrameParent); - if (nsLineLayout::TreatFrameAsBlock(prevFrameParent)) { - // The previous frame's parent is an anonymous block. This means - // that the new block frames can be safely inserted there. - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(prevFrameParent); - frame->GetNextSibling(&frame); - } - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = (nsAnonymousBlockFrame*) prevFrameParent; - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - aPrevFrame, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 3\n"); -#endif - } - else { - // The previous frame's parent is an inline frame. First see if - // there is an anonymous block before the insertion point. - nsInlineFrame* flow = (nsInlineFrame*) prevFrameParent; - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = flow->FindPrevAnonymousBlock(&flow); - if (nsnull != anonymousBlock) { - // We found an anonymous block before the insertion - // point. Take all of the inline frames between the anonymous - // block and prevFrameParent and strip them away from the - // inline frames that contain them. - nsFrameList frames; - nsInlineFrame* start; - flow->GetNextInFlow((nsIFrame**) &start); // start after anon block - while (start != prevFrameParent) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - - // Now append the frames just before and including aPrevFrame - // to "frames". - flow = (nsInlineFrame*) prevFrameParent; - nsIFrame* remainingFrames; - flow->mFrames.Split(aPrevFrame, &remainingFrames); - frames.AppendFrames(anonymousBlock, flow->mFrames); - flow->mFrames.SetFrames(remainingFrames); - generateReflowCommand = PR_TRUE; - target = flow; - - // Finally, append the block frames to "frames" and then - // append the list of frames to the anonymous block. - frames.AppendFrames(anonymousBlock, aFrameList); - anonymousBlock->AppendFrames2(&aPresContext, &aPresShell, nsnull, - frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 4\n"); -#endif - } - else { - // There is no anymous block before the insertion point. See - // if there is one after the insertion point. - flow = (nsInlineFrame*) prevFrameParent; - anonymousBlock = flow->FindAnonymousBlock(&flow); - if (nsnull != anonymousBlock) { - // We found an anonymous block after the insertion - // point. Seed the list of frames to put into the anonymous - // block with the block frames being inserted. - nsFrameList frames; - frames.AppendFrames(anonymousBlock, aFrameList); - nsInlineFrame* start = (nsInlineFrame*) prevFrameParent; - - // Take the frames after aPrevFrame and place them at the - // end of the frames list. - nsIFrame* remainingFrames; - start->mFrames.Split(aPrevFrame, &remainingFrames); - if (remainingFrames) { - frames.AppendFrames(anonymousBlock, remainingFrames); - } - generateReflowCommand = PR_TRUE; - target = start; - - // Gather up all of the inline frames from all of the flow - // between the insertion point and the anonymous block. - start->GetNextInFlow((nsIFrame**) &start); - while (start != flow) { - frames.AppendFrames(anonymousBlock, start->mFrames); - start->GetNextInFlow((nsIFrame**) &start); - } - - // Now update the anonymous block - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - nsnull, frames.FirstChild()); -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 5\n"); -#endif - } - else { - // There are no anonymous blocks so create one and place the - // frames into it. - nsIFrame* anonBlock; - rv = CreateAnonymousBlock(aPresContext, aFrameList, &anonBlock); - if (NS_FAILED(rv)) { - return rv; - } - - // Insert the frame into the correct parent (it will not be - // this frame when aPrevFrame's parent != this) - flow = (nsInlineFrame*) prevFrameParent; - flow->mFrames.InsertFrames(flow, aPrevFrame, anonBlock); - generateReflowCommand = PR_TRUE; - target = flow; -#ifdef NOISY_ANON_BLOCK - printf("InsertBlockFrames: case 6\n"); -#endif - } - } - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - return rv; -} - -nsresult -nsInlineFrame::InsertInlineFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - if (nsnull == aPrevFrame) { - // Insert the frames at the front of our list. Since the frames - // are all inline frames we just place them there, even if our - // current first frame is the anonymous block frame. The reflow - // logic will properly push the anonymous block frame to a - // next-in-flow. - mFrames.InsertFrames(this, nsnull, aFrameList); - generateReflowCommand = PR_TRUE; - target = this; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 1\n"); -#endif - } - else { - nsIFrame* prevFrameParent; - aPrevFrame->GetParent(&prevFrameParent); - if (nsLineLayout::TreatFrameAsBlock(prevFrameParent)) { - nsAnonymousBlockFrame* anonymousBlock; - anonymousBlock = (nsAnonymousBlockFrame*) prevFrameParent; - - // The previous frame's parent is an anonymous block (otherwise - // its parent would be this frame). We must not place the inline - // frames into the anonymous block if they should be in - // section3. - nsIFrame* nextSibling; - aPrevFrame->GetNextSibling(&nextSibling); - nsIFrame* anonymousBlockNextInFlow; - prevFrameParent->GetNextInFlow(&anonymousBlockNextInFlow); - if ((nsnull != nextSibling) || (nsnull != anonymousBlockNextInFlow)) { - // Easy case: there are more frames following aPrevFrame which - // means that this insertion lies in the anonymous block. - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(anonymousBlock); - frame->GetNextSibling(&frame); - } - anonymousBlock->InsertFrames2(&aPresContext, &aPresShell, nsnull, - aPrevFrame, aFrameList); -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 2\n"); -#endif - } - else { - // aPrevFrame is the last frame that should be in the - // anonymous block. - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**)&anonymousBlockParent); - - // Place the inline frames after the anonymous block - nsIFrame* frame = aFrameList; - while (nsnull != frame) { - frame->SetParent(anonymousBlockParent); - frame->GetNextSibling(&frame); - } - anonymousBlockParent->mFrames.InsertFrames(nsnull, anonymousBlock, - aFrameList); - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 3\n"); -#endif - } - } - else { - // The previous frame's parent is an inline frame. Therefore - // this is either a section1 or section3 insertion. Insert the - // frames in the proper flow block (which will be aPrevFrame's - // parent which is currently stored in anonymousBlock) - nsInlineFrame* flow = (nsInlineFrame*) prevFrameParent; - flow->mFrames.InsertFrames(flow, aPrevFrame, aFrameList); - generateReflowCommand = PR_TRUE; - target = flow; -#ifdef NOISY_ANON_BLOCK - printf("InsertInlineFrames: case 4\n"); -#endif - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - if (nsnull != aListName) { - return NS_ERROR_INVALID_ARG; - } - -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": remove "); - nsFrame::ListTag(stdout, aOldFrame); - printf("\n"); -#endif - - nsresult rv = NS_OK; - PRBool generateReflowCommand = PR_FALSE; - nsIFrame* target = nsnull; - - nsIFrame* oldFrameParent; - if (ParentIsInlineFrame(aOldFrame, &oldFrameParent)) { - // Loop and destroy the frame and all of its - // continuations. Because the frame's parent is an inline frame we - // know that any continuations will also be in an inline frame - // parent. - nsInlineFrame* parent = (nsInlineFrame*) oldFrameParent; - while (nsnull != aOldFrame) { - // If the frame being removed has zero size then don't bother - // generating a reflow command. - nsRect bbox; - aOldFrame->GetRect(bbox); - if ((0 == bbox.width) && (0 == bbox.height)) { - // Don't bother generating a reflow command - } - else { - generateReflowCommand = PR_TRUE; - target = this; - } - - // When the parent is an inline frame we have a simple task - - // just remove the frame from its parents list and generate a - // reflow command. - nsIFrame* oldFrameNextInFlow; - aOldFrame->GetNextInFlow(&oldFrameNextInFlow); - nsSplittableType st; - aOldFrame->IsSplittable(st); - if (NS_FRAME_NOT_SPLITTABLE != st) { - nsSplittableFrame::RemoveFromFlow(aOldFrame); - } - parent->mFrames.DestroyFrame(aPresContext, aOldFrame); - aOldFrame = oldFrameNextInFlow; - if (nsnull != aOldFrame) { - aOldFrame->GetParent((nsIFrame**) &parent); - } - } -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 1\n"); -#endif - } - else { -#ifdef DEBUG - nsIFrame* oldFrameNextInFlow; - aOldFrame->GetNextInFlow(&oldFrameNextInFlow); - NS_ASSERTION(nsnull == oldFrameNextInFlow, "XXX: can't remove continued frames that are in anonymous blocks -- not yet implemented"); -#endif - - nsIFrame* nextInFlow; - nsIFrame* prevInFlow; - - // The parent is not an inline frame which means it is an - // anonymous block frame. - nsAnonymousBlockFrame* anonymousBlock = - (nsAnonymousBlockFrame*) oldFrameParent; - - // It is possible that we are about to remove the last child of - // the anonymous block. In this case we remove the anonymous block. - nsIFrame* kids; - anonymousBlock->FirstChild(nsnull, &kids); - nsFrameList blockKids(kids); - if (1 == blockKids.GetLength()) { - // Remove the anonymous block - mFrames.DestroyFrame(aPresContext, anonymousBlock); - generateReflowCommand = PR_TRUE; - target = this; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 2\n"); -#endif - } - else { - // If the frame being removed is a block frame then we may need to - // do something fancy. - if (nsLineLayout::TreatFrameAsBlock(aOldFrame)) { - // It is possible that we are removing the first block in the - // anonymous block or the last block. See if its so. - anonymousBlock->GetPrevInFlow(&prevInFlow); - nsIFrame* prevSib; - if ((nsnull != prevInFlow) || - (nsnull != (prevSib = blockKids.GetPrevSiblingFor(aOldFrame)))) { - // There is a block in the anonymous block prior to the - // block that we are removing. See if we are removing the - // last block in the anonymous block. - anonymousBlock->GetNextInFlow(&nextInFlow); - nsIFrame* nextSib; - aOldFrame->GetNextSibling(&nextSib); - if ((nsnull != nextInFlow) || (nsnull != nextSib)) { - // There is a block in the anonymous block after the block - // that we are removing. This means that we can let the - // anonymous block remove the frame. -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 3\n"); -#endif - anonymousBlock->RemoveFrame2(&aPresContext, &aPresShell, aListName, - aOldFrame); - } - else { - // We are removing the last block. We must steal all of - // the inline frames that preceed the block being removed - // (up to the closest prior block) so that they can be - // moved outside the anonymous block and into an inline - // frame. - - // First get the last frame out of the picture; delete any - // continuations it might have. - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**) &anonymousBlockParent); - nsAnonymousBlockFrame* ab = anonymousBlock; - anonymousBlock->RemoveFramesFrom(aOldFrame); - aOldFrame->Destroy(aPresContext); - while (nsnull != nextInFlow) { - nsIFrame* nextParent; - nextInFlow->GetParent(&nextParent); - if (nextParent != ab) { - ab = (nsAnonymousBlockFrame*) nextParent; - } - ab->RemoveFirstFrame(); - nsIFrame* nextNextInFlow; - nextInFlow->GetNextInFlow(&nextNextInFlow); - nextInFlow->Destroy(aPresContext); - nextInFlow = nextNextInFlow; - } - - // Any inline frames that are between the new last-block - // inside the anonymous block and the block we just - // removed need to be taken out of the anonymous block. - nsFrameList inlines; - while (nsnull != anonymousBlock) { - // Find the first inline before the last block - nsIFrame* abkids; - anonymousBlock->FirstChild(nsnull, &abkids); - if (nsnull != abkids) { - SectionData sd(abkids); - if (sd.HasABlock()) { - abkids = sd.lastBlock; - abkids->GetNextSibling(&abkids); - if (nsnull != abkids) { - // Take the frames that follow the last block - // (which are inline frames) and remove them from - // the anonymous block. Insert them into the - // inlines frame-list. - anonymousBlock->RemoveFramesFrom(abkids); - inlines.InsertFrames(nsnull, nsnull, abkids); - } - } - else { - // All of the frames are inline frames -- take them - // all away. - anonymousBlock->RemoveFramesFrom(abkids); - inlines.InsertFrames(nsnull, nsnull, abkids); - } - } - anonymousBlock->GetPrevInFlow((nsIFrame**) &anonymousBlock); - } - - // Now we have all of the inline frames that need to be - // placed into an inline parent instead of the anonymous - // block parent. - if (inlines.NotEmpty()) { - // Place the inline frames after the anonymous block - // frame in the child list of the anonymousBlockParent. - anonymousBlockParent->mFrames.AppendFrames(anonymousBlockParent, - inlines); - } - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 4\n"); -#endif - } - } - else { - // We are removing the first block child of the anonymous - // block. We must gather all of the inline frames that - // follow the block being removed from the anonymous block - // so that they can be moved outside the anonymous block and - // into an inline frame. - - // Take away the first frame from the anonymous block (which - // is the frame we are trying to remove). Make sure we - // remove aOldFrame's continuations if it has any... - nsInlineFrame* anonymousBlockParent; - anonymousBlock->GetParent((nsIFrame**) &anonymousBlockParent); - anonymousBlock->RemoveFirstFrame(); - aOldFrame->GetNextInFlow(&nextInFlow); - aOldFrame->Destroy(aPresContext); - while (nsnull != nextInFlow) { - nsIFrame* nextParent; - nextInFlow->GetParent(&nextParent); - if (nextParent != anonymousBlock) { - anonymousBlock = (nsAnonymousBlockFrame*) nextParent; - } - anonymousBlock->RemoveFirstFrame(); - nsIFrame* nextNextInFlow; - nextInFlow->GetNextInFlow(&nextNextInFlow); - nextInFlow->Destroy(aPresContext); - nextInFlow = nextNextInFlow; - } - - // Gather up the inline frames that follow aOldFrame - nsFrameList frames; - PRBool done = PR_FALSE; - while (!done && (nsnull != anonymousBlock)) { - nsIFrame* kid; - anonymousBlock->FirstChild(nsnull, &kid); - while (nsnull != kid) { - if (nsLineLayout::TreatFrameAsBlock(kid)) { - done = PR_TRUE; - break; - } - nsIFrame* next; - kid->GetNextSibling(&next); - anonymousBlock->RemoveFirstFrame(); - frames.AppendFrame(nsnull, kid); - kid = next; - } - anonymousBlock->GetNextInFlow((nsIFrame**) &anonymousBlock); - } - - if (frames.NotEmpty()) { - // If the anonymousBlockParent has a prev-in-flow then - // append the inline frames there, otherwise insert them - // before the anonymousBlock. - anonymousBlockParent->GetPrevInFlow(&prevInFlow); - if (nsnull != prevInFlow) { - anonymousBlockParent = (nsInlineFrame*) prevInFlow; - anonymousBlockParent->mFrames.AppendFrames(anonymousBlockParent, - frames); - } - else { - anonymousBlockParent->mFrames.InsertFrames(anonymousBlockParent, - nsnull, - frames); - } - } - generateReflowCommand = PR_TRUE; - target = anonymousBlockParent; -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 5\n"); -#endif - } - } - else { - // We can let the anonymousBlock remove the frame directly -#ifdef NOISY_ANON_BLOCK - printf("RemoveFrame: case 6\n"); -#endif - anonymousBlock->RemoveFrame2(&aPresContext, &aPresShell, aListName, - aOldFrame); - } - } - } - - if (generateReflowCommand) { - // generate a reflow command for "this" - nsIReflowCommand* reflowCmd = nsnull; - rv = NS_NewHTMLReflowCommand(&reflowCmd, target, - nsIReflowCommand::ReflowDirty); - if (NS_SUCCEEDED(rv)) { - aPresShell.AppendReflowCommand(reflowCmd); - NS_RELEASE(reflowCmd); - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// -// Reflow methods - -NS_IMETHODIMP -nsInlineFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - if (nsnull == aReflowState.mLineLayout) { - return NS_ERROR_INVALID_ARG; - } - DrainOverflow(&aPresContext); - - if (IsFrameTreeTooDeep(aReflowState, aMetrics)) { -#ifdef DEBUG_kipp - { - extern char* nsPresShell_ReflowStackPointerTop; - char marker; - char* newsp = (char*) ▮ - printf("XXX: frame tree is too deep; approx stack size = %d\n", - nsPresShell_ReflowStackPointerTop - newsp); - } -#endif - aStatus = NS_FRAME_COMPLETE; - return NS_OK; - } - - // Set our own reflow state (additional state above and beyond - // aReflowState) - InlineReflowState irs; - irs.mPrevFrame = nsnull; - irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; - irs.mNextRCFrame = nsnull; - if (eReflowReason_Incremental == aReflowState.reason) { - // Peel off the next frame in the path if this is an incremental - // reflow aimed at one of the children. - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this != target) { - aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); - } - } - - nsresult rv; - if (mFrames.IsEmpty()) { - // Try to pull over one frame before starting so that we know - // whether we have an anonymous block or not. - (void) PullAnyFrame(&aPresContext, irs); - } - - if (HaveAnonymousBlock()) { - if (!aReflowState.mLineLayout->LineIsEmpty()) { - // This inline frame cannot be placed on the current line - // because there already is an inline frame on this line (and we - // contain an anonymous block). - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - rv = NS_OK; - } - else { - rv = ReflowBlockFrame(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear - // it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - } - } - else { - rv = ReflowInlineFrames(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - // Note: when we are reflowing inline frames the line layout code - // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for - // us. - } - - return rv; -} - -NS_IMETHODIMP -nsInlineFrame::FindTextRuns(nsLineLayout& aLineLayout) -{ - if (HaveAnonymousBlock()) { - aLineLayout.EndTextRun(); - } - else { - nsIFrame* frame = mFrames.FirstChild(); - while (nsnull != frame) { - frame->FindTextRuns(aLineLayout); - frame->GetNextSibling(&frame); - } - } - return NS_OK; -} - -void -nsInlineFrame::DrainOverflow(nsIPresContext* aPresContext) -{ - // Check for an overflow list with our prev-in-flow - nsInlineFrame* prevInFlow = (nsInlineFrame*)mPrevInFlow; - if (nsnull != prevInFlow) { - nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); - - if (prevOverflowFrames) { - // When pushing and pulling frames we need to check for whether any - // views need to be reparented. - for (nsIFrame* f = prevOverflowFrames; f; f->GetNextSibling(&f)) { - nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevInFlow, this); - } - mFrames.InsertFrames(this, nsnull, prevOverflowFrames); - } - } - - // It's also possible that we have an overflow list for ourselves - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); - if (overflowFrames) { - NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); - mFrames.AppendFrames(nsnull, overflowFrames); - } -} - -nsresult -nsInlineFrame::ReflowInlineFrames(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; - aStatus = NS_FRAME_COMPLETE; - - nsLineLayout* lineLayout = aReflowState.mLineLayout; - nscoord leftEdge = 0; - if (nsnull == mPrevInFlow) { - leftEdge = aReflowState.mComputedBorderPadding.left; - } - nscoord availableWidth = aReflowState.availableWidth; - if (NS_UNCONSTRAINEDSIZE != availableWidth) { - // Subtract off left and right border+padding from availableWidth - availableWidth -= leftEdge; - availableWidth -= aReflowState.mComputedBorderPadding.right; - } - lineLayout->BeginSpan(this, &aReflowState, - leftEdge, leftEdge + availableWidth); - - // First reflow our current children - nsIFrame* frame = mFrames.FirstChild(); - PRBool done = PR_FALSE; - while (nsnull != frame) { - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); - if (NS_FAILED(rv)) { - done = PR_TRUE; - break; - } - if (NS_FRAME_COMPLETE != aStatus) { - if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { - done = PR_TRUE; - break; - } - } - irs.mPrevFrame = frame; - frame->GetNextSibling(&frame); - } - - // Attempt to pull frames from our next-in-flow until we can't - if (!done && (nsnull != mNextInFlow)) { - while (!done) { - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - PRBool isComplete; - frame = PullInlineFrame(aPresContext, irs, &isComplete); - if (nsnull == frame) { - if (!isComplete) { - aStatus = NS_FRAME_NOT_COMPLETE; - } - break; - } - rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus); - if (NS_FAILED(rv)) { - done = PR_TRUE; - break; - } - if (NS_FRAME_COMPLETE != aStatus) { - if (!reflowingFirstLetter || NS_INLINE_IS_BREAK(aStatus)) { - done = PR_TRUE; - break; - } - } - irs.mPrevFrame = frame; - } - } -#ifdef DEBUG - if (NS_FRAME_COMPLETE == aStatus) { - // We can't be complete AND have overflow frames! - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_FALSE); - NS_ASSERTION(!overflowFrames, "whoops"); - } -#endif - - // If after reflowing our children they take up no area then make - // sure that we don't either. - // - // Note: CSS demands that empty inline elements still affect the - // line-height calculations. However, continuations of an inline - // that are empty we force to empty so that things like collapsed - // whitespace in an inline element don't affect the line-height. - nsSize size; - lineLayout->EndSpan(this, size, aMetrics.maxElementSize); - if ((0 == size.height) && (0 == size.width) && - ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { - // This is a continuation of a previous inline. Therefore make - // sure we don't affect the line-height. - aMetrics.width = 0; - aMetrics.height = 0; - aMetrics.ascent = 0; - aMetrics.descent = 0; - if (nsnull != aMetrics.maxElementSize) { - aMetrics.maxElementSize->width = 0; - aMetrics.maxElementSize->height = 0; - } - } - else { - // Compute final width - aMetrics.width = size.width; - if (nsnull == mPrevInFlow) { - aMetrics.width += aReflowState.mComputedBorderPadding.left; - } - if (NS_FRAME_IS_COMPLETE(aStatus)) { - aMetrics.width += aReflowState.mComputedBorderPadding.right; - } - - const nsStyleFont* font; - GetStyleData(eStyleStruct_Font, (const nsStyleStruct*&)font); - aReflowState.rendContext->SetFont(font->mFont); - nsCOMPtr fm; - aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm)); - - // Compute final height of the frame. - // - // Do things the standard css2 way -- though it's hard to find it - // in the css2 spec! It's actually found in the css1 spec section - // 4.4 (you will have to read between the lines to really see - // it). - // - // The height of our box is the sum of our font size plus the top - // and bottom border and padding. The height of children do not - // affect our height. - fm->GetMaxAscent(aMetrics.ascent); - fm->GetMaxDescent(aMetrics.descent); - fm->GetHeight(aMetrics.height); - aMetrics.ascent += aReflowState.mComputedBorderPadding.top; - aMetrics.descent += aReflowState.mComputedBorderPadding.bottom; - aMetrics.height += aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; - - // Note: we normally use the actual font height for computing the - // line-height raw value from the style context. On systems where - // they disagree the actual font height is more appropriate. This - // little hack lets us override that behavior to allow for more - // precise layout in the face of imprecise fonts. - if (nsHTMLReflowState::UseComputedHeight()) { - aMetrics.height = font->mFont.size + - aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.bottom; - } - } - - // For now our combined area is zero. The real value will be - // computed during vertical alignment of the line we are on. - aMetrics.mCombinedArea.x = 0; - aMetrics.mCombinedArea.y = 0; - aMetrics.mCombinedArea.width = aMetrics.width; - aMetrics.mCombinedArea.height = aMetrics.height; - -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": metrics=%d,%d ascent=%d descent=%d\n", - aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); -#endif - - return rv; -} - -nsresult -nsInlineFrame::ReflowInlineFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsIFrame* aFrame, - nsReflowStatus& aStatus) -{ - // Make sure that we don't reflow a block frame when we run across - // one. This can easily happen if this inline has a mixture of - // frames (note that an anonymous block frame is used to wrap up the - // direct block children of this inline therefore when we do run - // across a block frame its an anonymous block). - if (nsLineLayout::TreatFrameAsBlock(aFrame)) { - NS_ASSERTION(aFrame != mFrames.FirstChild(), "bad anon-block status"); - PushFrames(aPresContext, aFrame, irs.mPrevFrame); - aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_NOT_COMPLETE); - return NS_OK; - } - - nsLineLayout* lineLayout = aReflowState.mLineLayout; - PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); - nsresult rv = lineLayout->ReflowFrame(aFrame, &irs.mNextRCFrame, aStatus); - if (NS_FAILED(rv)) { - return rv; - } - if (NS_INLINE_IS_BREAK(aStatus)) { - if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { - if (aFrame != mFrames.FirstChild()) { - // Change break-before status into break-after since we have - // already placed at least one child frame. This preserves the - // break-type so that it can be propogated upward. - aStatus = NS_FRAME_NOT_COMPLETE | - NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | - (aStatus & NS_INLINE_BREAK_TYPE_MASK); - PushFrames(aPresContext, aFrame, irs.mPrevFrame); - } - else { - // Preserve reflow status when breaking-before our first child - // and propogate it upward without modification. - } - } - else { - // Break-after - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - } - nsIFrame* nextFrame; - aFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - aStatus |= NS_FRAME_NOT_COMPLETE; - PushFrames(aPresContext, nextFrame, aFrame); - } - else if (nsnull != mNextInFlow) { - // We must return an incomplete status if there are more child - // frames remaining in a next-in-flow that follows this frame. - nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->mFrames.NotEmpty()) { - aStatus |= NS_FRAME_NOT_COMPLETE; - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - } - } - } - else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, aFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - if (!reflowingFirstLetter) { - nsIFrame* nextFrame; - aFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - PushFrames(aPresContext, nextFrame, aFrame); - } - } - } - return rv; -} - -nsIFrame* -nsInlineFrame::PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& irs, - PRBool* aIsComplete) -{ - PRBool isComplete = PR_TRUE; - - nsIFrame* frame = nsnull; - nsInlineFrame* nextInFlow = irs.mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->HaveAnonymousBlock()) { - isComplete = PR_FALSE; - break; - } - frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); - if (nsnull != frame) { - isComplete = PR_FALSE; - nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - irs.mNextInFlow = nextInFlow; - } - - *aIsComplete = isComplete; - return frame; -} - -nsIFrame* -nsInlineFrame::PullAnyFrame(nsIPresContext* aPresContext, - InlineReflowState& irs) -{ - nsIFrame* frame = nsnull; - nsInlineFrame* nextInFlow = irs.mNextInFlow; - while (nsnull != nextInFlow) { - frame = mFrames.PullFrame(this, irs.mPrevFrame, nextInFlow->mFrames); - if (nsnull != frame) { - nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); - break; - } - - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - irs.mNextInFlow = nextInFlow; - } - - return frame; -} - -void -nsInlineFrame::PushFrames(nsIPresContext* aPresContext, - nsIFrame* aFromChild, - nsIFrame* aPrevSibling) -{ - NS_PRECONDITION(nsnull != aFromChild, "null pointer"); - NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child"); -#ifdef DEBUG - nsIFrame* prevNextSibling; - aPrevSibling->GetNextSibling(&prevNextSibling); - NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); -#endif - - // Disconnect aFromChild from its previous sibling - aPrevSibling->SetNextSibling(nsnull); - - // Add the frames to our overflow list (let our next in flow drain - // our overflow list when it is ready) - SetOverflowFrames(aPresContext, aFromChild); -} - -nsresult -nsInlineFrame::ReflowBlockFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& irs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus) -{ - nsIFrame* blockFrame = mFrames.FirstChild(); - - // Compute available area -#if XXX_what_to_do - nscoord x = aReflowState.mComputedBorderPadding.left; - nscoord availableWidth = aReflowState.availableWidth; - if (NS_UNCONSTRAINEDSIZE != availableWidth) { - if (nsnull != mPrevInFlow) { - x = 0; - availableWidth -= aReflowState.mComputedBorderPadding.right; - } - else { - availableWidth -= aReflowState.mComputedBorderPadding.left + - aReflowState.mComputedBorderPadding.right; - } - } - nscoord y = aReflowState.mComputedBorderPadding.top; - nscoord availableHeight = aReflowState.availableHeight; - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) { - availableHeight -= aReflowState.mComputedBorderPadding.top + - aReflowState.mComputedBorderPadding.right; - } -#else - nscoord x = 0; - nscoord availableWidth = aReflowState.availableWidth; - nscoord y = 0; - nscoord availableHeight = aReflowState.availableHeight; -#endif - - // XXX_ib write me... -//XXX nscoord collapsedTopMargin = 0; - nscoord collapsedBottomMargin = 0; - - // Reflow the block frame - nsBlockReflowContext bc(aPresContext, aReflowState, - nsnull != aMetrics.maxElementSize); - bc.SetNextRCFrame(irs.mNextRCFrame); - nsRect availSpace(x, y, availableWidth, availableHeight); - PRBool isAdjacentWithTop = PR_FALSE; - nsMargin computedOffsets; - nsresult rv = bc.ReflowBlock(blockFrame, availSpace, PR_FALSE, 0, - isAdjacentWithTop, - computedOffsets, aStatus); - if (NS_FAILED(rv)) { - return rv; - } - if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) { - // We need to break before placing the block so propogate that - // status outward to our parent. - } - else { - // Place the block (during placement we might discover that none - // of it fits) - nsRect bounds; - PRBool anyFit = bc.PlaceBlock(isAdjacentWithTop, - computedOffsets, &collapsedBottomMargin, - bounds, aMetrics.mCombinedArea); - if (!anyFit) { - // None of the block fit - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - } - else { - if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { - // When the block isn't complete create a continuation for it - nsIFrame* newFrame; - rv = CreateNextInFlow(*aPresContext, this, blockFrame, newFrame); - if (NS_FAILED(rv)) { - return rv; - } - } - - // It's possible that the block frame is followed by one or more - // inline frames. Make sure we reflect that in our reflow status - // and push them to our next-in-flow. - nsIFrame* nextFrame; - blockFrame->GetNextSibling(&nextFrame); - if (nsnull != nextFrame) { - PushFrames(aPresContext, nextFrame, blockFrame); - aStatus |= NS_FRAME_NOT_COMPLETE; - } - else if (NS_FRAME_IS_COMPLETE(aStatus)) { - // When the block we reflowed is complete then we need to - // check and see if there are other frames (inline frames) - // following in our continuations so that we return the proper - // reflow status. - nsInlineFrame* nextInFlow = (nsInlineFrame*) mNextInFlow; - while (nsnull != nextInFlow) { - if (nextInFlow->mFrames.NotEmpty() || - nextInFlow->GetOverflowFrames(aPresContext, PR_FALSE)) { - aStatus |= NS_FRAME_NOT_COMPLETE; - break; - } - nextInFlow = (nsInlineFrame*) nextInFlow->mNextInFlow; - } - } - - // What we do here is to fudge the size. This frame will - // be 0,0 but will contain a single child (the anonymous block) - // that is properly sized. - aMetrics.width = bounds.width; - aMetrics.height = bounds.height; - aMetrics.ascent = bounds.height; - aMetrics.descent = 0; - aMetrics.mCarriedOutBottomMargin = bc.GetCarriedOutBottomMargin(); - if (nsnull != aMetrics.maxElementSize) { - *aMetrics.maxElementSize = bc.GetMaxElementSize(); - } - } - } - - return NS_OK; -} - -////////////////////////////////////////////////////////////////////// - -PRIntn -nsInlineFrame::GetSkipSides() const -{ - PRIntn skip = 0; - if (nsnull != mPrevInFlow) { - nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow; - if (prev->mRect.height || prev->mRect.width) { - // Prev-in-flow is not empty therefore we don't render our left - // border edge. - skip |= 1 << NS_SIDE_LEFT; - } - else { - // If the prev-in-flow is empty, then go ahead and let our right - // edge border render. - } - } - if (nsnull != mNextInFlow) { - nsInlineFrame* next = (nsInlineFrame*) mNextInFlow; - if (next->mRect.height || next->mRect.width) { - // Next-in-flow is not empty therefore we don't render our right - // border edge. - skip |= 1 << NS_SIDE_RIGHT; - } - else { - // If the next-in-flow is empty, then go ahead and let our right - // edge border render. - } - } - return skip; -} - -////////////////////////////////////////////////////////////////////// - -// nsLineFrame implementation - -static void -ReParentChildListStyle(nsIPresContext* aPresContext, - nsIStyleContext* aParentStyleContext, - nsFrameList& aFrameList) -{ - nsIFrame* kid = aFrameList.FirstChild(); - while (nsnull != kid) { - aPresContext->ReParentStyleContext(kid, aParentStyleContext); - kid->GetNextSibling(&kid); - } -} - -nsresult -NS_NewFirstLineFrame(nsIFrame** aNewFrame) -{ - NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); - if (nsnull == aNewFrame) { - return NS_ERROR_NULL_POINTER; - } - nsInlineFrame* it = new nsFirstLineFrame; - if (nsnull == it) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNewFrame = it; - return NS_OK; -} - -nsFirstLineFrame::nsFirstLineFrame() -{ -} - -NS_IMETHODIMP -nsFirstLineFrame::GetFrameName(nsString& aResult) const -{ - return MakeFrameName("Line", aResult); -} - -NS_IMETHODIMP -nsFirstLineFrame::GetFrameType(nsIAtom** aType) const -{ - NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); - *aType = nsLayoutAtoms::lineFrame; - NS_ADDREF(*aType); - return NS_OK; -} - -NS_IMETHODIMP -nsFirstLineFrame::AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->AppendFrames(aPresContext, aPresShell, aListName, - aFrameList); -#else - nsresult rv = nsInlineFrame::AppendFrames(aPresContext, aPresShell, - aListName, aFrameList); -// nsFrameList frames(aFrameList); -// ReResolveChildList(&aPresContext, mStyleContext, frames); - return rv; -#endif -} - -NS_IMETHODIMP -nsFirstLineFrame::InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->InsertFrames(aPresContext, aPresShell, aListName, - aPrevFrame, aFrameList); -#else - nsresult rv = nsInlineFrame::InsertFrames(aPresContext, aPresShell, - aListName, aPrevFrame, aFrameList); -// nsFrameList frames(aFrameList); -// ReResolveChildList(&aPresContext, mStyleContext, frames); - return rv; -#endif -} - -NS_IMETHODIMP -nsFirstLineFrame::RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ -#ifdef BLOCK_DOES_FIRST_LINE - return mParent->RemoveFrame(aPresContext, aPresShell, aListName, - aOldFrame); -#else - nsresult rv = nsInlineFrame::RemoveFrame(aPresContext, aPresShell, - aListName, aOldFrame); - return rv; -#endif -} - -#ifdef BLOCK_DOES_FIRST_LINE -nsresult -nsFirstLineFrame::AppendFrames2(nsIPresContext* aPresContext, - nsIFrame* aFrameList) -{ - nsFrameList frames(aFrameList); - ReParentChildListStyle(aPresContext, mStyleContext, frames); - // XXX ReparentFrameView - mFrames.AppendFrames(this, aFrameList); - return NS_OK; -} - -nsresult -nsFirstLineFrame::InsertFrames2(nsIPresContext* aPresContext, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList) -{ - nsFrameList frames(aFrameList); - ReParentChildListStyle(aPresContext, mStyleContext, frames); - // XXX ReparentFrameView - mFrames.InsertFrames(this, aPrevFrame, aFrameList); - return NS_OK; -} - -nsresult -nsFirstLineFrame::RemoveFrame2(nsIPresContext* aPresContext, - nsIFrame* aOldFrame) -{ - nsIFrame* nextInFlow; - aOldFrame->GetNextInFlow(&nextInFlow); - if (nextInFlow) { - DeleteChildsNextInFlow(*aPresContext, aOldFrame); - } - mFrames.RemoveFrame(aOldFrame); - return NS_OK; -} -#endif - -void -nsFirstLineFrame::StealFramesFrom(nsIFrame* aFrame) -{ - nsIFrame* prevFrame = mFrames.GetPrevSiblingFor(aFrame); - if (prevFrame) { - prevFrame->SetNextSibling(nsnull); - } - else { - mFrames.SetFrames(nsnull); - } -} - -nsIFrame* -nsFirstLineFrame::PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& irs, - PRBool* aIsComplete) -{ - nsIFrame* frame = - nsInlineFrame::PullInlineFrame(aPresContext, irs, aIsComplete); - if (frame && !mPrevInFlow) { - // We are a first-line frame. Fixup the child frames - // style-context that we just pulled. - aPresContext->ReParentStyleContext(frame, mStyleContext); - } - return frame; -} - -void -nsFirstLineFrame::DrainOverflow(nsIPresContext* aPresContext) -{ - // Check for an overflow list with our prev-in-flow - nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)mPrevInFlow; - if (nsnull != prevInFlow) { - nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext, PR_TRUE); - if (prevOverflowFrames) { - nsFrameList frames(prevOverflowFrames); - - ReParentChildListStyle(aPresContext, mStyleContext, frames); - mFrames.InsertFrames(this, nsnull, prevOverflowFrames); - } - } - - // It's also possible that we have an overflow list for ourselves - nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); - if (overflowFrames) { - NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); - nsFrameList frames(overflowFrames); - - ReParentChildListStyle(aPresContext, mStyleContext, frames); - mFrames.AppendFrames(nsnull, overflowFrames); - } -} - -NS_IMETHODIMP -nsFirstLineFrame::Reflow(nsIPresContext& aPresContext, - nsHTMLReflowMetrics& aMetrics, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - if (nsnull == aReflowState.mLineLayout) { - return NS_ERROR_INVALID_ARG; - } - DrainOverflow(&aPresContext); - - // Set our own reflow state (additional state above and beyond - // aReflowState) - InlineReflowState irs; - irs.mPrevFrame = nsnull; - irs.mNextInFlow = (nsInlineFrame*) mNextInFlow; - irs.mNextRCFrame = nsnull; - if (eReflowReason_Incremental == aReflowState.reason) { - // Peel off the next frame in the path if this is an incremental - // reflow aimed at one of the children. - nsIFrame* target; - aReflowState.reflowCommand->GetTarget(target); - if (this != target) { - aReflowState.reflowCommand->GetNext(irs.mNextRCFrame); - } - } - - nsresult rv; - PRBool wasEmpty = mFrames.IsEmpty(); - if (wasEmpty) { - // Try to pull over one frame before starting so that we know - // whether we have an anonymous block or not. - PullAnyFrame(&aPresContext, irs); - } - - if (HaveAnonymousBlock()) { - if (!aReflowState.mLineLayout->LineIsEmpty()) { - // This inline frame cannot be placed on the current line - // because there already is an inline frame on this line (and we - // contain an anonymous block). - aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - rv = NS_OK; - } - else { - rv = ReflowBlockFrame(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear - // it. - if ((aMetrics.mCombinedArea.x < 0) || - (aMetrics.mCombinedArea.y < 0) || - (aMetrics.mCombinedArea.XMost() > aMetrics.width) || - (aMetrics.mCombinedArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - } - } - else { - if (wasEmpty) { - // Fixup style of frame just pulled up - nsIFrame* firstFrame = mFrames.FirstChild(); - if (firstFrame) { - aPresContext.ReParentStyleContext(firstFrame, mStyleContext); - } - } - if (nsnull == mPrevInFlow) { - // XXX This is pretty sick, but what we do here is to pull-up, in - // advance, all of the next-in-flows children. We re-resolve their - // style while we are at at it so that when we reflow they have - // the right style. - // - // All of this is so that text-runs reflow properly. - irs.mPrevFrame = mFrames.LastChild(); - for (;;) { - PRBool complete; - nsIFrame* frame = PullInlineFrame(&aPresContext, irs, &complete); - if (!frame) { - break; - } - irs.mPrevFrame = frame; - } - irs.mPrevFrame = nsnull; - } - else { -// XXX do this in the Init method instead - // For continuations, we need to check and see if our style - // context is right. If its the same as the first-in-flow, then - // we need to fix it up (that way :first-line style doesn't leak - // into this continuation since we aren't the first line). - nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow(); - if (mStyleContext == first->mStyleContext) { - // Fixup our style context and our children. First get the - // proper parent context. - nsIFrame* parentFrame; - first->GetParent(&parentFrame); - nsIStyleContext* parentContext; - parentFrame->GetStyleContext(&parentContext); - if (parentContext) { - // Create a new style context that is a child of the parent - // style context thus removing the :first-line style. This way - // we behave as if an anonymous (unstyled) span was the child - // of the parent frame. - nsIStyleContext* newSC; - aPresContext.ResolvePseudoStyleContextFor(mContent, - nsHTMLAtoms::mozLineFrame, - parentContext, - PR_FALSE, &newSC); - if (newSC) { - // Switch to the new style context. - SetStyleContext(&aPresContext, newSC); - - // Re-resolve all children - ReParentChildListStyle(&aPresContext, mStyleContext, mFrames); - - NS_RELEASE(newSC); - } - NS_RELEASE(parentContext); - } - } - } - - rv = ReflowInlineFrames(&aPresContext, aReflowState, irs, - aMetrics, aStatus); - // Note: when we are reflowing inline frames the line layout code - // will properly compute our NS_FRAME_OUTSIDE_CHILDREN state for - // us. - } - - return rv; -} - #ifdef DEBUG NS_IMETHODIMP -nsPositionedInlineFrame::SizeOf(nsISizeOfHandler* aHandler, - PRUint32* aResult) const +nsPositionedInlineFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const { if (!aResult) { return NS_ERROR_NULL_POINTER; diff --git a/layout/html/base/src/nsInlineFrame.h b/layout/html/base/src/nsInlineFrame.h index 7a55d14fd266..2fcd9f0ddaca 100644 --- a/layout/html/base/src/nsInlineFrame.h +++ b/layout/html/base/src/nsInlineFrame.h @@ -30,6 +30,12 @@ class nsAnonymousBlockFrame; #define nsInlineFrameSuper nsHTMLContainerFrame +/** + * Inline frame class. + * + * This class manages a list of child frames that are inline frames. Working with + * nsLineLayout, the class will reflow and place inline frames on a line. + */ class nsInlineFrame : public nsInlineFrameSuper { public: @@ -39,9 +45,6 @@ public: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); // nsIFrame overrides - NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, - nsIAtom* aListName, - nsIFrame* aChildList); NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, nsIPresShell& aPresShell, nsIAtom* aListName, @@ -55,7 +58,11 @@ public: nsIPresShell& aPresShell, nsIAtom* aListName, nsIFrame* aOldFrame); - NS_IMETHOD Destroy(nsIPresContext& aPresContext); + NS_IMETHOD ReplaceFrame(nsIPresContext& aPresContext, + nsIPresShell& aPresShell, + nsIAtom* aListName, + nsIFrame* aOldFrame, + nsIFrame* aNewFrame); NS_IMETHOD GetFrameName(nsString& aResult) const; NS_IMETHOD GetFrameType(nsIAtom** aType) const; @@ -65,15 +72,15 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout); -#if XXX_fix_me - NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace); - NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext, - nsIRenderingContext& aRC, - nscoord& aDeltaWidth); -#endif static nsIID kInlineFrameCID; + // Take all of the frames away from this frame. The caller is + // presumed to keep them alive. + void StealAllFrames() { + mFrames.SetFrames(nsnull); + } + protected: // Additional reflow state used during our reflow methods struct InlineReflowState { @@ -82,75 +89,15 @@ protected: nsInlineFrame* mNextInFlow; }; - // A helper class that knows how to take a list of frames and chop - // it up into 3 sections. - struct SectionData { - SectionData(nsIFrame* aFrameList); - - PRBool SplitFrameList(nsFrameList& aSection1, - nsFrameList& aSection2, - nsFrameList& aSection3); - - PRBool HasABlock() const { - return nsnull != firstBlock; - } - - nsIFrame* firstBlock; - nsIFrame* prevFirstBlock; - nsIFrame* lastBlock; - nsIFrame* firstFrame; - nsIFrame* lastFrame; - }; - nsInlineFrame(); virtual PRIntn GetSkipSides() const; - PRBool HaveAnonymousBlock() const { - return mFrames.NotEmpty() - ? nsLineLayout::TreatFrameAsBlock(mFrames.FirstChild()) - : PR_FALSE; - } - - static PRBool ParentIsInlineFrame(nsIFrame* aFrame, nsIFrame** aParent) { - void* tmp; - nsIFrame* parent; - aFrame->GetParent(&parent); - *aParent = parent; - if (NS_SUCCEEDED(parent->QueryInterface(kInlineFrameCID, &tmp))) { - return PR_TRUE; - } - return PR_FALSE; - } - - nsAnonymousBlockFrame* FindPrevAnonymousBlock(nsInlineFrame** aBlockParent); - - nsAnonymousBlockFrame* FindAnonymousBlock(nsInlineFrame** aBlockParent); - - nsresult CreateAnonymousBlock(nsIPresContext& aPresContext, - nsIFrame* aFrameList, - nsIFrame** aResult); - - nsresult AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aFrameList, - PRBool aGenerateReflowCommands); - - nsresult InsertBlockFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult InsertInlineFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult ReflowInlineFrames(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& rs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus); + nsresult ReflowFrames(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + InlineReflowState& rs, + nsHTMLReflowMetrics& aMetrics, + nsReflowStatus& aStatus); nsresult ReflowInlineFrame(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -158,29 +105,23 @@ protected: nsIFrame* aFrame, nsReflowStatus& aStatus); - virtual nsIFrame* PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& rs, - PRBool* aIsComplete); + virtual nsIFrame* PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& rs, + PRBool* aIsComplete); virtual void PushFrames(nsIPresContext* aPresContext, nsIFrame* aFromChild, nsIFrame* aPrevSibling); virtual void DrainOverflow(nsIPresContext* aPresContext); - - nsIFrame* PullAnyFrame(nsIPresContext* aPresContext, InlineReflowState& rs); - - nsresult ReflowBlockFrame(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - InlineReflowState& rs, - nsHTMLReflowMetrics& aMetrics, - nsReflowStatus& aStatus); }; //---------------------------------------------------------------------- -// Variation on inline-frame used to manage lines for line layout in -// special situations. +/** + * Variation on inline-frame used to manage lines for line layout in + * special situations (:first-line style in particular). + */ class nsFirstLineFrame : public nsInlineFrame { public: friend nsresult NS_NewFirstLineFrame(nsIFrame** aNewFrame); @@ -192,62 +133,20 @@ public: const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); -#ifdef BLOCK_DOES_FIRST_LINE - // AppendFrames/InsertFrames/RemoveFrame are implemented to forward - // the method call to the parent frame. -#endif - NS_IMETHOD AppendFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aFrameList); - NS_IMETHOD InsertFrames(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - NS_IMETHOD RemoveFrame(nsIPresContext& aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - -#ifdef BLOCK_DOES_FIRST_LINE - // These methods are used by the parent frame to actually modify the - // child frames of the line frame. These methods do not generate - // reflow commands. - nsresult AppendFrames2(nsIPresContext* aPresContext, - nsIFrame* aFrameList); - - nsresult InsertFrames2(nsIPresContext* aPresContext, - nsIFrame* aPrevFrame, - nsIFrame* aFrameList); - - nsresult RemoveFrame2(nsIPresContext* aPresContext, - nsIFrame* aOldFrame); - -#endif // Take frames starting at aFrame until the end of the frame-list // away from this frame. The caller is presumed to keep them alive. void StealFramesFrom(nsIFrame* aFrame); - // Take all of the frames away from this frame. The caller is - // presumed to keep them alive. - void StealAllFrames() { - mFrames.SetFrames(nsnull); - } - protected: nsFirstLineFrame(); - virtual nsIFrame* PullInlineFrame(nsIPresContext* aPresContext, - InlineReflowState& rs, - PRBool* aIsComplete); + virtual nsIFrame* PullOneFrame(nsIPresContext* aPresContext, + InlineReflowState& rs, + PRBool* aIsComplete); virtual void DrainOverflow(nsIPresContext* aPresContext); }; -extern nsresult NS_NewFirstLineFrame(nsIFrame** aNewFrame); - - //---------------------------------------------------------------------- // Derived class created for relatively positioned inline-level elements diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index 255343986cc1..016d2e772569 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -92,6 +92,12 @@ #include "nsDocument.h" #include "nsToolbarItemFrame.h" +#ifdef DEBUG +static PRBool gNoisyContentUpdates = PR_FALSE; +static PRBool gReallyNoisyContentUpdates = PR_FALSE; +static PRBool gNoisyInlineConstruction = PR_FALSE; +#endif + nsresult NS_NewThumbFrame ( nsIFrame** aNewFrame ); @@ -1844,8 +1850,7 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresContext* aPresContext, const nsStyleDisplay* childDisplay = (const nsStyleDisplay*) childStyleContext->GetStyleData(eStyleStruct_Display); if (IsTableRelated(childDisplay->mDisplay)) { - rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, aChildItems); } else { nsCOMPtr tag; aChildContent->GetTag(*getter_AddRefs(tag)); @@ -1864,12 +1869,10 @@ nsCSSFrameConstructor::TableProcessChild(nsIPresContext* aPresContext, if (parentDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE) { nsIFrame* outerFrame; aParentFrame->GetParent(&outerFrame); - rv = ConstructFrame(aPresContext, aState, aChildContent, outerFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, outerFrame, aChildItems); // XXX: Seems like this is going into the inner frame's child list instead of the outer frame. - DWH } else { - rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, - PR_FALSE, aChildItems); + rv = ConstructFrame(aPresContext, aState, aChildContent, aParentFrame, aChildItems); } // wrap it in a table cell, row, row group, table if it is a valid tag or display // and not whitespace. For example we don't allow map, head, body, etc. @@ -2072,7 +2075,7 @@ nsCSSFrameConstructor::ConstructDocElementTableFrame(nsIPresContext* aPresContex nsFrameConstructorState state(aPresContext, nsnull, nsnull, nsnull); nsFrameItems frameItems; - ConstructFrame(aPresContext, state, aDocElement, aParentFrame, PR_FALSE, frameItems); + ConstructFrame(aPresContext, state, aDocElement, aParentFrame, frameItems); aNewTableFrame = frameItems.childList; return NS_OK; } @@ -3602,7 +3605,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresContext* aPresConte content->SetDocument(aDocument, PR_TRUE); // create the frame and attach it to our frame - ConstructFrame(aPresContext, aState, content, aNewFrame, PR_FALSE, aChildItems); + ConstructFrame(aPresContext, aState, content, aNewFrame, aChildItems); } return NS_OK; @@ -3726,7 +3729,7 @@ nsCSSFrameConstructor::CreateAnonymousTreeCellFrames(nsIPresContext* aPresConte content->SetDocument(doc, PR_TRUE); // create the frame and attach it to our frame - ConstructFrame(aPresContext, aState, content, aNewFrame, PR_FALSE, aChildItems); + ConstructFrame(aPresContext, aState, content, aNewFrame, aChildItems); } if (count > 0) { @@ -4423,7 +4426,6 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems) { @@ -4433,6 +4435,8 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre PRBool isFloating = PR_FALSE; PRBool isBlock = aDisplay->IsBlockLevel(); nsIFrame* newFrame = nsnull; // the frame we construct + nsIFrame* newBlock = nsnull; + nsIFrame* nextInline = nsnull; nsTableCreator tableCreator; // Used to make table frames. PRBool addToHashTable = PR_TRUE; nsresult rv = NS_OK; @@ -4699,7 +4703,8 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre if (NS_SUCCEEDED(rv)) { // That worked so construct the inline and its children rv = ConstructInline(aPresContext, aState, aDisplay, aContent, - aParentFrame, aStyleContext, newFrame); + aParentFrame, aStyleContext, newFrame, + &newBlock, &nextInline); } // To keep the hash table small don't add inline frames (they're @@ -4814,6 +4819,12 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre } else if (nsnull != newFrame) { // Add the frame we just created to the flowed list aFrameItems.AddChild(newFrame); + if (newBlock) { + aFrameItems.AddChild(newBlock); + if (nextInline) { + aFrameItems.AddChild(nextInline); + } + } } if (newFrame && addToHashTable) { @@ -4827,78 +4838,6 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresContext* aPre return rv; } -nsresult -nsCSSFrameConstructor::ConstructBlock(nsIPresContext* aPresContext, - nsFrameConstructorState& aState, - const nsStyleDisplay* aDisplay, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame) -{ - // Initialize the frame - aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, - nsnull); - - // See if we need to create a view, e.g. the frame is absolutely positioned - nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, - aStyleContext, PR_FALSE); - - // See if the block has first-letter style applied to it... - PRBool haveFirstLetterStyle, haveFirstLineStyle; - HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, - &haveFirstLetterStyle, &haveFirstLineStyle); - - // Process the child content - nsFrameItems childItems; - nsFrameConstructorSaveState floaterSaveState; - aState.PushFloaterContainingBlock(aNewFrame, floaterSaveState, - haveFirstLetterStyle, - haveFirstLineStyle); - nsresult rv = ProcessChildren(aPresContext, aState, aContent, aNewFrame, - PR_TRUE, childItems, PR_TRUE); - - // Set the frame's initial child list - aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); - - // Set the frame's floater list if there were any floated children - if (aState.mFloatedItems.childList) { - aNewFrame->SetInitialChildList(*aPresContext, - nsLayoutAtoms::floaterList, - aState.mFloatedItems.childList); - } - - return rv; -} - -nsresult -nsCSSFrameConstructor::ConstructInline(nsIPresContext* aPresContext, - nsFrameConstructorState& aState, - const nsStyleDisplay* aDisplay, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame) -{ - // Initialize the frame - aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, - nsnull); - - // See if we need to create a view, e.g. the frame is absolutely positioned - nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, - aStyleContext, PR_FALSE); - - // Process the child content - nsFrameItems childItems; - nsresult rv = ProcessChildren(aPresContext, aState, aContent, - aNewFrame, PR_TRUE, childItems, PR_FALSE); - - // Set the frame's initial child list - aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); - - return rv; -} - nsresult nsCSSFrameConstructor::GetAdjustedParentFrame(nsIFrame* aCurrentParentFrame, PRUint8 aChildDisplayType, @@ -5201,7 +5140,6 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresContext* aPresContext, nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems) { @@ -5261,8 +5199,7 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresContext* aPresContext, // When there is no explicit frame to create, assume it's a // container and let display style dictate the rest rv = ConstructFrameByDisplayType(aPresContext, aState, display, aContent, - aParentFrame, styleContext, - aHaveFirstLetterStyle, aFrameItems); + aParentFrame, styleContext, aFrameItems); } } } @@ -5564,96 +5501,21 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, nsnull, aFrameList); } -// See if aContent is the "logical" first child of -// aContainingBlock. The check works recursively, skipping upward -// through content until we reach aContainingBlock. -static PRBool -ContentIsLogicalFirstChild(nsIContent* aContent, nsIContent* aContainingBlock) -{ - if (aContent) { - nsCOMPtr contentParent; - aContent->GetParent(*getter_AddRefs(contentParent)); - if (contentParent) { - PRInt32 ix; - contentParent->IndexOf(aContent, ix); - if (0 != ix) { - return PR_FALSE; - } - if (contentParent.get() != aContainingBlock) { - return ContentIsLogicalFirstChild(contentParent, aContainingBlock); - } - return PR_TRUE; - } - } - return PR_FALSE; -} - -nsresult -nsCSSFrameConstructor::MaybeCreateContainerFrame(nsIPresContext* aPresContext, - nsIContent* aContainer) -{ - nsresult rv = NS_OK; -#if 0 - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - - // See if aContainer's parent has a frame... - nsCOMPtr containerParent; - aContainer->GetParent(*getter_AddRefs(containerParent)); - if (containerParent) { - nsIFrame* parentFrame = GetFrameFor(shell, aPresContext, containerParent); - if (parentFrame) { - // aContainer's parent has a frame. Maybe aContainer needs a - // frame now? If it's display none, then it doesn't. - nsCOMPtr parentStyleContext; - parentFrame->GetStyleContext(getter_AddRefs(parentStyleContext)); - nsCOMPtr styleContext; - aPresContext->ResolveStyleContextFor(aContainer, parentStyleContext, - PR_FALSE, - getter_AddRefs(styleContext)); - const nsStyleDisplay* display = (const nsStyleDisplay*) - styleContext->GetStyleData(eStyleStruct_Display); - if (NS_STYLE_DISPLAY_NONE != display->mDisplay) { - // aContainer's display is not none and it has a parent - // frame. Now we see if it needs a frame after new content - // was appended. - if (IsHTMLParagraph(aContainer)) { - if (!IsEmptyContainer(aContainer)) { - // It's an HTML paragraph (P) and it has some - // content. Because of the previous checks we now know - // that the P used to have nothing but empty content and - // therefore had no frame created. This condition is no - // longer true so we create a frame for aContainer (and - // its children) and insert them into the tree... - PRInt32 ix; - containerParent->IndexOf(aContainer, ix); - if (ix >= 0) { -#ifdef DEBUG_kipp - printf("Recreating frame for HTML:P\n"); -#endif - ContentInserted(aPresContext, containerParent, aContainer, ix); - } - } - } - } - } - else { - // If aContainer's parent has no frame then there is no need - // in trying to create a frame for aContainer. - } - } - else { - // aContainer has no parent. Odd. - } -#endif - return rv; -} - NS_IMETHODIMP nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, nsIContent* aContainer, PRInt32 aNewIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentAppended container=%p index=%d\n", + aContainer, aNewIndexInContainer); + if (gReallyNoisyContentUpdates && aContainer) { + aContainer->List(stdout, 0); + } + } +#endif + nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); @@ -5694,6 +5556,28 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // Get the frame associated with the content nsIFrame* parentFrame = GetFrameFor(shell, aPresContext, aContainer); if (nsnull != parentFrame) { + + // If the frame we are manipulating is a special frame then do + // something different instead of just appending newly created + // frames. Note that only the first-in-flow is marked so we check + // before getting to the last-in-flow. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentAppended: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + // Get the parent frame's last-in-flow nsIFrame* nextInFlow = parentFrame; while (nsnull != nextInFlow) { @@ -5744,8 +5628,7 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, aContainer->ChildAt(i, *getter_AddRefs(childContent)); // Construct a child frame - ConstructFrame(aPresContext, state, childContent, parentFrame, - PR_FALSE, frameItems); + ConstructFrame(aPresContext, state, childContent, parentFrame, frameItems); } if (haveFirstLineStyle) { @@ -5772,6 +5655,13 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // Notify the parent frame passing it the list of new frames if (NS_SUCCEEDED(result) && firstAppendedFrame) { + // Perform special check for diddling around with the frames in + // a special inline frame. + if (WipeContainingBlock(aPresContext, state, blockContent, adjustedParentFrame, + frameItems.childList)) { + return NS_OK; + } + // Append the flowed frames to the principal child list AppendFrames(aPresContext, shell, state.mFrameManager, aContainer, adjustedParentFrame, firstAppendedFrame); @@ -5782,8 +5672,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mAbsoluteItems.childList) { state.mAbsoluteItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::absoluteList, - state.mAbsoluteItems.childList); + nsLayoutAtoms::absoluteList, + state.mAbsoluteItems.childList); } // If there are new fixed positioned child frames, then notify @@ -5792,8 +5682,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mFixedItems.childList) { state.mFixedItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::fixedList, - state.mFixedItems.childList); + nsLayoutAtoms::fixedList, + state.mFixedItems.childList); } // If there are new floating child frames, then notify @@ -5802,8 +5692,8 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, // determine where in the list they should be inserted... if (state.mFloatedItems.childList) { state.mFloatedItems.containingBlock->AppendFrames(*aPresContext, *shell, - nsLayoutAtoms::floaterList, - state.mFloatedItems.childList); + nsLayoutAtoms::floaterList, + state.mFloatedItems.childList); } // Recover first-letter frames @@ -5826,12 +5716,6 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext, } } - else { - // Since the parentFrame wasn't found, aContainer didn't have a - // frame created for it. Maybe now that it has a new child it - // should get a frame... - MaybeCreateContainerFrame(aPresContext, aContainer); - } return NS_OK; } @@ -5983,12 +5867,22 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted container=%p child=%p index=%d\n", + aContainer, aChild, aIndexInContainer); + if (gReallyNoisyContentUpdates) { + (aContainer ? aContainer : aChild)->List(stdout, 0); + } + } +#endif + #ifdef INCLUDE_XUL if (aContainer) { nsCOMPtr tag; aContainer->GetTag(*getter_AddRefs(tag)); if (tag && (tag.get() == nsXULAtoms::treechildren || - tag.get() == nsXULAtoms::treeitem)) { + tag.get() == nsXULAtoms::treeitem)) { // Walk up to the outermost tree row group frame and tell it that // content was added. nsCOMPtr parent; @@ -6012,14 +5906,14 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsTreeRowGroupFrame* treeRowGroup = (nsTreeRowGroupFrame*)parentFrame; if (treeRowGroup && treeRowGroup->IsLazy()) { nsIFrame* nextSibling = FindNextSibling(shell, aContainer, aIndexInContainer); - if(!nextSibling) + if(!nextSibling) treeRowGroup->OnContentAdded(*aPresContext); - else { + else { nsIFrame* frame = GetFrameFor(shell, aPresContext, aContainer); nsTreeRowGroupFrame* frameTreeRowGroup = (nsTreeRowGroupFrame*)frame; - if(frameTreeRowGroup) + if(frameTreeRowGroup) frameTreeRowGroup->OnContentInserted(*aPresContext, nextSibling); - } + } return NS_OK; } } @@ -6065,13 +5959,6 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } else { -#if 0 - nsIFrame* nextSibling; - nsIFrame* prevSibling; - nsIFrame* parentFrame; - GetSiblingAndParent(shell, aContainer, aIndexInContainer, - &nextSibling, &prevSibling, &parentFrame); -#endif // Find the frame that precedes the insertion point. nsIFrame* prevSibling = FindPreviousSibling(shell, aContainer, aIndexInContainer); nsIFrame* nextSibling = nsnull; @@ -6110,6 +5997,26 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, // Construct a new frame if (nsnull != parentFrame) { + // If the frame we are manipulating is a special frame then do + // something different instead of just inserting newly created + // frames. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + nsFrameItems frameItems; nsFrameConstructorState state(aPresContext, mFixedContainingBlock, GetAbsoluteContainingBlock(aPresContext, parentFrame), @@ -6168,8 +6075,45 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } - rv = ConstructFrame(aPresContext, state, aChild, parentFrame, PR_FALSE, - frameItems); + // If the frame we are manipulating is a special inline frame + // then do something different instead of just inserting newly + // created frames. + if (IsFrameSpecial(state.mFrameManager, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. + nsCOMPtr parentContainer; + blockContent->GetParent(*getter_AddRefs(parentContainer)); +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentInserted: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special inline\n"); + printf(" ==> blockContent=%p, parentContainer=%p\n", + blockContent.get(), parentContainer.get()); + } +#endif + if (parentContainer) { + PRInt32 ix; + parentContainer->IndexOf(blockContent, ix); + ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); + } + else { + // XXX uh oh. the block that needs reworking has no parent... + } + return NS_OK; + } + + rv = ConstructFrame(aPresContext, state, aChild, parentFrame, frameItems); + + // Perform special check for diddling around with the frames in + // a special inline frame. + if (WipeContainingBlock(aPresContext, state, blockContent, parentFrame, frameItems.childList)) { + return NS_OK; + } if (haveFirstLineStyle) { // It's possible that the new frame goes into a first-line @@ -6189,6 +6133,7 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, nsIFrame* newFrame = frameItems.childList; if (NS_SUCCEEDED(rv) && (nsnull != newFrame)) { + // Notify the parent frame if (isAppend) { rv = AppendFrames(aPresContext, shell, state.mFrameManager, @@ -6251,12 +6196,6 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } - else { - // Since the parentFrame wasn't found, aContainer didn't have a - // frame created for it. Maybe now that it has a new child it - // should get a frame... - MaybeCreateContainerFrame(aPresContext, aContainer); - } // Here we have been notified that content has been insert // so if the select now has a single item @@ -6424,6 +6363,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, nsIContent* aChild, PRInt32 aIndexInContainer) { +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p index=%d\n", + aContainer, aChild, aIndexInContainer); + if (gReallyNoisyContentUpdates) { + aContainer->List(stdout, 0); + } + } +#endif + nsCOMPtr shell; aPresContext->GetShell(getter_AddRefs(shell)); nsCOMPtr frameManager; @@ -6524,28 +6473,31 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, } #endif // INCLUDE_XUL -#if 0 - // It's possible that we just made an HTML paragraph empty... - if (IsEmptyHTMLParagraph(aContainer)) { - nsCOMPtr containerParent; - aContainer->GetParent(*getter_AddRefs(containerParent)); - if (containerParent) { - PRInt32 ix; - containerParent->IndexOf(aContainer, ix); - if (ix >= 0) { - // No point in doing the fixup - needFixup = PR_FALSE; - rv = ContentRemoved(aPresContext, containerParent, aContainer, ix); - } - } - } -#endif - if (childFrame) { // Get the childFrame's parent frame nsIFrame* parentFrame; childFrame->GetParent(&parentFrame); + // If the frame we are manipulating is a special frame then do + // something different instead of just inserting newly created + // frames. + if (IsFrameSpecial(aPresContext, parentFrame)) { + // We are pretty harsh here (and definitely not optimal) -- we + // wipe out the entire containing block and recreate it from + // scratch. The reason is that because we know that a special + // inline frame has propogated some of its children upward to be + // children of the block and that those frames may need to move + // around. This logic guarantees a correct answer. +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::ContentRemoved: parentFrame="); + nsFrame::ListTag(stdout, parentFrame); + printf(" is special\n"); + } +#endif + return ReframeContainingBlock(aPresContext, parentFrame); + } + // Examine the containing-block for the removed content and see if // :first-letter style applies. nsIFrame* containingBlock = @@ -7578,7 +7530,7 @@ nsCSSFrameConstructor::CantRenderReplacedElement(nsIPresContext* aPresContext, // Note: if the old frame was out-of-flow, then so will the new frame // and we'll get a new placeholder frame rv = ConstructFrameByDisplayType(aPresContext, state, display, content, - inFlowParent, styleContext, PR_FALSE, frameItems); + inFlowParent, styleContext, frameItems); if (NS_SUCCEEDED(rv)) { nsIFrame* newFrame = frameItems.childList; @@ -8231,52 +8183,17 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresContext* aPresContext, } } - PRBool whitespaceDoesntMatter = PR_FALSE; - PRBool okToSkip = PR_FALSE; - if (aParentIsBlock) { - const nsStyleText* st; - aFrame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) st); - whitespaceDoesntMatter = !st->WhiteSpaceIsSignificant(); - okToSkip = whitespaceDoesntMatter; - } - // Iterate the child content objects and construct frames PRInt32 count; aContent->ChildCount(count); for (PRInt32 i = 0; i < count; i++) { nsCOMPtr childContent; if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { - if (aParentIsBlock) { -#if 0 - if (okToSkip && IsEmptyTextContent(childContent)) { - continue; - } -#endif -#if 0 - if (whitespaceDoesntMatter && IsEmptyHTMLParagraph(childContent)) { - continue; - } -#endif - } - // Construct a child frame - okToSkip = PR_FALSE; - rv = ConstructFrame(aPresContext, aState, childContent, aFrame, i == 0, - aFrameItems); + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); if (NS_FAILED(rv)) { return rv; } - - // If last frame was a blockish type of frame, then its ok to - // skip the next empty text content. - if (aParentIsBlock && whitespaceDoesntMatter && aFrameItems.lastChild) { - const nsStyleDisplay* sd; - aFrameItems.lastChild->GetStyleData(eStyleStruct_Display, - (const nsStyleStruct*&) sd); - if (sd->IsBlockLevel()) { - okToSkip = PR_TRUE; - } - } } } @@ -8291,14 +8208,13 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresContext* aPresContext, } } - if (aParentIsBlock && aState.mFirstLetterStyle) { - rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, - aFrame, aFrameItems); - } - - if (aParentIsBlock && aState.mFirstLineStyle) { - rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, - aFrameItems); + if (aParentIsBlock) { + if (aState.mFirstLetterStyle) { + rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + if (aState.mFirstLineStyle) { + rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } } return rv; @@ -9274,8 +9190,7 @@ nsCSSFrameConstructor::CreateTreeWidgetContent(nsIPresContext* aPresContext, nsFrameConstructorState state(aPresContext, mFixedContainingBlock, GetAbsoluteContainingBlock(aPresContext, aParentFrame), GetFloaterContainingBlock(aPresContext, aParentFrame)); - rv = ConstructFrame(aPresContext, state, aChild, aParentFrame, PR_FALSE, - frameItems); + rv = ConstructFrame(aPresContext, state, aChild, aParentFrame, frameItems); nsIFrame* newFrame = frameItems.childList; *aNewFrame = newFrame; @@ -9324,4 +9239,546 @@ nsCSSFrameConstructor::CreateTreeWidgetContent(nsIPresContext* aPresContext, return rv; } +//---------------------------------------------------------------------- +// Block/inline frame construction logic. We maintain a few invariants here: +// +// 1. Block frames contain block and inline frames. +// +// 2. Inline frames only contain inline frames. If an inline parent has a block +// child then the block child is migrated upward until it lands in a block +// parent (the inline frames containing block is where it will end up). + +// XXX consolidate these things +static PRBool +IsBlockFrame(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + const nsStyleDisplay* display; + aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display); + if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) { + return PR_FALSE; + } + return PR_TRUE; +} + +static nsIFrame* +FindFirstBlock(nsIPresContext* aPresContext, nsIFrame* aKid, nsIFrame** aPrevKid) +{ + nsIFrame* prevKid = nsnull; + while (aKid) { + if (IsBlockFrame(aPresContext, aKid)) { + *aPrevKid = prevKid; + return aKid; + } + prevKid = aKid; + aKid->GetNextSibling(&aKid); + } + *aPrevKid = nsnull; + return nsnull; +} + +static nsIFrame* +FindLastBlock(nsIPresContext* aPresContext, nsIFrame* aKid) +{ + nsIFrame* lastBlock = nsnull; + while (aKid) { + if (IsBlockFrame(aPresContext, aKid)) { + lastBlock = aKid; + } + aKid->GetNextSibling(&aKid); + } + return lastBlock; +} + +static nsresult +MoveChildrenTo(nsIPresContext* aPresContext, + nsIStyleContext* aNewParentSC, + nsIFrame* aNewParent, + nsIFrame* aFrameList) +{ + while (aFrameList) { + aFrameList->SetParent(aNewParent); + aFrameList->GetNextSibling(&aFrameList); + } + return NS_OK; +} + +//---------------------------------------- + +nsresult +nsCSSFrameConstructor::ConstructBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + const nsStyleDisplay* aDisplay, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame* aNewFrame) +{ + // Initialize the frame + aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, + nsnull); + + // See if we need to create a view, e.g. the frame is absolutely positioned + nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, aNewFrame, + aStyleContext, PR_FALSE); + + // See if the block has first-letter style applied to it... + PRBool haveFirstLetterStyle, haveFirstLineStyle; + HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, + &haveFirstLetterStyle, &haveFirstLineStyle); + + // Process the child content + nsFrameItems childItems; + nsFrameConstructorSaveState floaterSaveState; + aState.PushFloaterContainingBlock(aNewFrame, floaterSaveState, + haveFirstLetterStyle, + haveFirstLineStyle); + nsresult rv = ProcessBlockChildren(aPresContext, aState, aContent, aNewFrame, + PR_TRUE, childItems, PR_TRUE); + + // Set the frame's initial child list + aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); + + // Set the frame's floater list if there were any floated children + if (aState.mFloatedItems.childList) { + aNewFrame->SetInitialChildList(*aPresContext, + nsLayoutAtoms::floaterList, + aState.mFloatedItems.childList); + } + + return rv; +} + +nsresult +nsCSSFrameConstructor::ProcessBlockChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool aParentIsBlock) +{ + nsresult rv = NS_OK; + nsCOMPtr styleContext; + + if (aCanHaveGeneratedContent) { + // Probe for generated content before + nsIFrame* generatedFrame; + aFrame->GetStyleContext(getter_AddRefs(styleContext)); + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::beforePseudo, + aParentIsBlock, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + // Iterate the child content objects and construct frames + PRInt32 count; + aContent->ChildCount(count); + for (PRInt32 i = 0; i < count; i++) { + nsCOMPtr childContent; + if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { + // Construct a child frame + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); + if (NS_FAILED(rv)) { + return rv; + } + } + } + + if (aCanHaveGeneratedContent) { + // Probe for generated content after + nsIFrame* generatedFrame; + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::afterPseudo, + aParentIsBlock, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + if (aParentIsBlock) { + if (aState.mFirstLetterStyle) { + rv = WrapFramesInFirstLetterFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + if (aState.mFirstLineStyle) { + rv = WrapFramesInFirstLineFrame(aPresContext, aState, aContent, aFrame, aFrameItems); + } + } + + return rv; +} + +// When inline frames get weird and have block frames in them, we +// annotate them to help us respond to incremental content changes +// more easily. + +static void +DestroyInlineFrameAnnotation(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIAtom* aPropertyName, + void* aPropertyValue) +{ +} + +PRBool +nsCSSFrameConstructor::IsFrameSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame) +{ + void* value; + nsresult rv = aFrameManager->GetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, 0, &value); + if (NS_OK == rv) { + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsCSSFrameConstructor::IsFrameSpecial(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + // Get to aFrame's first-in-flow; only the first-in-flow is marked + // with an annotation. + nsSplittableType splits; + aFrame->IsSplittable(splits); + if (splits != NS_FRAME_NOT_SPLITTABLE) { + nsIFrame* prevInFlow = aFrame; + while (prevInFlow) { + aFrame = prevInFlow; + prevInFlow->GetPrevInFlow(&prevInFlow); + } + } + + PRBool result = PR_FALSE; + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + void* value; + nsresult rv = frameManager->GetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, + 0, &value); + if (NS_OK == rv) { + result = PR_TRUE; + } + } + } + return result; +} + +void +nsCSSFrameConstructor::SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame) +{ + aFrameManager->SetFrameProperty(aFrame, nsLayoutAtoms::inlineFrameAnnotation, + (void*) PR_TRUE, DestroyInlineFrameAnnotation); +} + +PRBool +nsCSSFrameConstructor::AreAllKidsInline(nsIFrame* aFrameList) +{ + nsIFrame* kid = aFrameList; + while (kid) { + if (!IsInlineFrame(kid)) { + return PR_FALSE; + } + kid->GetNextSibling(&kid); + } + return PR_TRUE; +} + +nsresult +nsCSSFrameConstructor::ConstructInline(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + const nsStyleDisplay* aDisplay, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame* aNewFrame, + nsIFrame** aNewBlockFrame, + nsIFrame** aNextInlineFrame) +{ + // Initialize the frame + aNewFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, nsnull); + + // Process the child content + nsFrameItems childItems; + PRBool kidsAllInline; + nsresult rv = ProcessInlineChildren(aPresContext, aState, aContent, + aNewFrame, PR_TRUE, childItems, &kidsAllInline); + if (kidsAllInline) { + // Set the inline frame's initial child list + aNewFrame->SetInitialChildList(*aPresContext, nsnull, childItems.childList); + *aNewBlockFrame = nsnull; + *aNextInlineFrame = nsnull; + return rv; + } + + // This inline frame contains several types of children. Therefore + // this frame has to be chopped into several pieces. We will produce + // as a result of this 3 lists of children. The first list contains + // all of the inline children that preceed the first block child + // (and may be empty). The second list contains all of the block + // children and any inlines that are between them (and must not be + // empty, otherwise - why are we here?). The final list contains all + // of the inline children that follow the final block child. + + // Find the first block child which defines list1 and list2 + nsIFrame* list1 = childItems.childList; + nsIFrame* prevToFirstBlock; + nsIFrame* list2 = FindFirstBlock(aPresContext, list1, &prevToFirstBlock); + if (prevToFirstBlock) { + prevToFirstBlock->SetNextSibling(nsnull); + } + else { + list1 = nsnull; + } + + // Find the last block child which defines the end of list2 and the + // start of list3 + nsIFrame* afterFirstBlock; + list2->GetNextSibling(&afterFirstBlock); + nsIFrame* list3 = nsnull; + nsIFrame* lastBlock = FindLastBlock(aPresContext, afterFirstBlock); + if (!lastBlock) { + lastBlock = list2; + } + lastBlock->GetNextSibling(&list3); + lastBlock->SetNextSibling(nsnull); + + // list1's frames belong to this inline frame so go ahead and take them + aNewFrame->SetInitialChildList(*aPresContext, nsnull, list1); + + // list2's frames belong to an anonymous block that we create right + // now. The anonymous block will be the parent of the block children + // of the inline. + nsIFrame* blockFrame; + NS_NewBlockFrame(&blockFrame); + nsCOMPtr blockSC; + aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::mozAnonymousBlock, + aStyleContext, PR_FALSE, + getter_AddRefs(blockSC)); + blockFrame->Init(*aPresContext, aContent, aParentFrame, blockSC, nsnull); + MoveChildrenTo(aPresContext, blockSC, blockFrame, list2); + blockFrame->SetInitialChildList(*aPresContext, nsnull, list2); + + // list3's frames belong to another inline frame + nsIFrame* inlineFrame = nsnull; + NS_NewInlineFrame(&inlineFrame); + inlineFrame->Init(*aPresContext, aContent, aParentFrame, aStyleContext, nsnull); + if (list3) { + // Reparent (cheaply) the frames in list3 - we don't have to futz + // with their style context because they already have the right one. + nsFrameList list; + list.AppendFrames(inlineFrame, list3); + } + inlineFrame->SetInitialChildList(*aPresContext, nsnull, list3); + + // Mark the 3 frames as special. That way if any of the + // append/insert/remove methods try to fiddle with the children, the + // containing block will be reframed instead. + SetFrameIsSpecial(aState.mFrameManager, aNewFrame); + SetFrameIsSpecial(aState.mFrameManager, blockFrame); + SetFrameIsSpecial(aState.mFrameManager, inlineFrame); + +#ifdef DEBUG + if (gNoisyInlineConstruction) { + printf("nsCSSFrameConstructor::ConstructInline:\n"); + printf(" ==> leading inline frame:\n"); + aNewFrame->List(aPresContext, stdout, 2); + printf(" ==> block frame:\n"); + blockFrame->List(aPresContext, stdout, 2); + printf(" ==> trailing inline frame:\n"); + inlineFrame->List(aPresContext, stdout, 2); + } +#endif + + *aNewBlockFrame = blockFrame; + *aNextInlineFrame = inlineFrame; + + return rv; +} + +nsresult +nsCSSFrameConstructor::ProcessInlineChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool* aKidsAllInline) +{ + nsresult rv = NS_OK; + nsCOMPtr styleContext; + + if (aCanHaveGeneratedContent) { + // Probe for generated content before + nsIFrame* generatedFrame; + aFrame->GetStyleContext(getter_AddRefs(styleContext)); + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::beforePseudo, + PR_FALSE, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + // Iterate the child content objects and construct frames + PRBool allKidsInline = PR_TRUE; + PRInt32 count; + aContent->ChildCount(count); + for (PRInt32 i = 0; i < count; i++) { + nsCOMPtr childContent; + if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) { + // Construct a child frame + nsIFrame* oldLastChild = aFrameItems.lastChild; + rv = ConstructFrame(aPresContext, aState, childContent, aFrame, aFrameItems); + if (NS_FAILED(rv)) { + return rv; + } + + // Examine newly added children (we may have added more than one + // child if the child was another inline frame that ends up + // being carved in 3 pieces) to maintain the allKidsInline flag. + if (allKidsInline) { + nsIFrame* kid; + if (oldLastChild) { + oldLastChild->GetNextSibling(&kid); + } + else { + kid = aFrameItems.childList; + } + while (kid) { + if (!IsInlineFrame(kid)) { + allKidsInline = PR_FALSE; + break; + } + kid->GetNextSibling(&kid); + } + } + } + } + + if (aCanHaveGeneratedContent) { + // Probe for generated content after + nsIFrame* generatedFrame; + if (CreateGeneratedContentFrame(aPresContext, aState, aFrame, aContent, + styleContext, nsCSSAtoms::afterPseudo, + PR_FALSE, &generatedFrame)) { + // Add the generated frame to the child list + aFrameItems.AddChild(generatedFrame); + } + } + + *aKidsAllInline = allKidsInline; + + return rv; +} + +PRBool +nsCSSFrameConstructor::WipeContainingBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aBlockContent, + nsIFrame* aFrame, + nsIFrame* aFrameList) +{ + // Before we go and append the frames, check for a special + // situation: an inline frame that will now contain block + // frames. This is a no-no and the frame construction logic knows + // how to fix this. + const nsStyleDisplay* parentDisplay; + aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&) parentDisplay); + if (NS_STYLE_DISPLAY_INLINE == parentDisplay->mDisplay) { + if (!AreAllKidsInline(aFrameList)) { + // Ok, reverse tracks: wipe out the frames we just created + nsFrameList tmp(aFrameList); + tmp.DestroyFrames(*aPresContext); + if (aState.mAbsoluteItems.childList) { + tmp.SetFrames(aState.mAbsoluteItems.childList); + tmp.DestroyFrames(*aPresContext); + } + if (aState.mFixedItems.childList) { + tmp.SetFrames(aState.mFixedItems.childList); + tmp.DestroyFrames(*aPresContext); + } + if (aState.mFloatedItems.childList) { + tmp.SetFrames(aState.mFloatedItems.childList); + tmp.DestroyFrames(*aPresContext); + } + + // Tell parent of the containing block to reformulate the + // entire block. This is painful and definitely not optimal + // but it will *always* get the right answer. + nsCOMPtr parentContainer; + aBlockContent->GetParent(*getter_AddRefs(parentContainer)); +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf("nsCSSFrameConstructor::WipeContainingBlock: aBlockContent=%p parentContainer=%p\n", + aBlockContent, parentContainer.get()); + } +#endif + if (parentContainer) { + PRInt32 ix; + parentContainer->IndexOf(aBlockContent, ix); + ContentReplaced(aPresContext, parentContainer, aBlockContent, aBlockContent, ix); + } + else { + // XXX uh oh. the block we need to reframe has no parent! + } + return PR_TRUE; + } + } + return PR_FALSE; +} + +nsresult +nsCSSFrameConstructor::ReframeContainingBlock(nsIPresContext* aPresContext, nsIFrame* aFrame) +{ + // Get the parent of the target frame. From there we look for the + // containing block in case the target frame is already a block + // (which can happen when an inline frame wraps some of its content + // in an anonymous block; see ConstructInline) + nsIFrame* parentFrame; + aFrame->GetParent(&parentFrame); + if (!parentFrame) { + return RecreateEntireFrameTree(aPresContext); + } + + // Now find the containing block + nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, parentFrame); + if (!containingBlock) { + return RecreateEntireFrameTree(aPresContext); + } + + // And get the containingBlock's content + nsCOMPtr blockContent; + containingBlock->GetContent(getter_AddRefs(blockContent)); + if (!blockContent) { + return RecreateEntireFrameTree(aPresContext); + } + + // Now find the containingBlock's content's parent + nsCOMPtr parentContainer; + blockContent->GetParent(*getter_AddRefs(parentContainer)); + if (!parentContainer) { + return RecreateEntireFrameTree(aPresContext); + } + +#ifdef DEBUG + if (gNoisyContentUpdates) { + printf(" ==> blockContent=%p, parentContainer=%p\n", + blockContent.get(), parentContainer.get()); + } +#endif + + PRInt32 ix; + parentContainer->IndexOf(blockContent, ix); + nsresult rv = ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); + return rv; +} + +nsresult +nsCSSFrameConstructor::RecreateEntireFrameTree(nsIPresContext* aPresContext) +{ + // XXX write me some day + return NS_OK; +} diff --git a/layout/html/style/src/nsCSSFrameConstructor.h b/layout/html/style/src/nsCSSFrameConstructor.h index 143a1fd9ba9d..dd6814dca21d 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.h +++ b/layout/html/style/src/nsCSSFrameConstructor.h @@ -148,7 +148,6 @@ protected: nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems); nsresult ConstructDocElementFrame(nsIPresContext* aPresContext, @@ -506,7 +505,6 @@ protected: nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - PRBool aHaveFirstLetterStyle, nsFrameItems& aFrameItems); nsresult GetAdjustedParentFrame(nsIFrame* aCurrentParentFrame, @@ -662,13 +660,49 @@ InitializeSelectFrame(nsIPresContext* aPresContext, nsIStyleContext* aStyleContext, nsIFrame* aNewFrame); + nsresult ProcessBlockChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool aParentIsBlock); + nsresult ConstructInline(nsIPresContext* aPresContext, nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay, nsIContent* aContent, nsIFrame* aParentFrame, nsIStyleContext* aStyleContext, - nsIFrame* aNewFrame); + nsIFrame* aNewFrame, + nsIFrame** aNewBlockFrame, + nsIFrame** aNextInlineFrame); + + nsresult ProcessInlineChildren(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* aContent, + nsIFrame* aFrame, + PRBool aCanHaveGeneratedContent, + nsFrameItems& aFrameItems, + PRBool* aKidsAllInline); + + PRBool AreAllKidsInline(nsIFrame* aFrameList); + + PRBool IsFrameSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame); + + PRBool IsFrameSpecial(nsIPresContext* aPresContext, nsIFrame* aFrame); + + void SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame); + + PRBool WipeContainingBlock(nsIPresContext* aPresContext, + nsFrameConstructorState& aState, + nsIContent* blockContent, + nsIFrame* aFrame, + nsIFrame* aFrameList); + + nsresult ReframeContainingBlock(nsIPresContext* aPresContext, nsIFrame* aFrame); + + nsresult RecreateEntireFrameTree(nsIPresContext* aPresContext); //---------------------------------------- @@ -757,9 +791,6 @@ InitializeSelectFrame(nsIPresContext* aPresContext, nsIFrame* aPrevSibling, nsFrameItems& aFrameItems); - nsresult MaybeCreateContainerFrame(nsIPresContext* aPresContext, - nsIContent* aContainer); - protected: nsIDocument* mDocument;