From 2cdb5cc2b9e4c1907209b933195273c541d58eaf Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Tue, 29 Aug 2006 22:20:41 +0000 Subject: [PATCH] Make popups that are kids of the root popup set have it as their parent; generally make them more like other out-of-flows. Remove various code that worked around them being different. Bug 349921, r+sr=roc git-svn-id: svn://10.0.0.236/trunk@208763 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/nsCSSFrameConstructor.cpp | 233 ++++++++---------- .../layout/xul/base/public/nsIPopupSetFrame.h | 8 +- .../layout/xul/base/src/nsPopupSetFrame.cpp | 48 ++++ mozilla/layout/xul/base/src/nsPopupSetFrame.h | 20 +- 4 files changed, 166 insertions(+), 143 deletions(-) diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 23771123bf5..6ef0a7b088c 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -1120,6 +1120,9 @@ public: // Whether the parent is a block (see ProcessChildren's aParentIsBlock) PRBool mCreatorIsBlock; + // The root box, if any. + nsIRootBox* mRootBox; + // Constructor // Use the passed-in history state. nsFrameConstructorState(nsIPresShell* aPresShell, @@ -1176,6 +1179,8 @@ public: * positioned * @param aCanBeFloated pass false if the frame isn't allowed to be * floated + * @param aIsOutOfFlowPopup pass true if the frame is an out-of-flow popup + * (XUL-only) * @throws NS_ERROR_OUT_OF_MEMORY if it happens. * @note If this method throws, that means that aNewFrame was not inserted * into any frame lists. Furthermore, this method will handle cleanup @@ -1189,7 +1194,8 @@ public: nsStyleContext* aStyleContext, nsIFrame* aParentFrame, PRBool aCanBePositioned = PR_TRUE, - PRBool aCanBeFloated = PR_TRUE); + PRBool aCanBeFloated = PR_TRUE, + PRBool aIsOutOfFlowPopup = PR_FALSE); // Push an nsIAnonymousContentCreator and its insertion node void PushAnonymousContentCreator(nsIFrame *aCreator, @@ -1226,7 +1232,8 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe mPseudoFrames(), mAnonymousCreator(nsnull), mInsertionContent(nsnull), - mCreatorIsBlock(PR_FALSE) + mCreatorIsBlock(PR_FALSE), + mRootBox(nsIRootBox::GetRootBox(aPresShell)) { } @@ -1245,7 +1252,8 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, mPseudoFrames(), mAnonymousCreator(nsnull), mInsertionContent(nsnull), - mCreatorIsBlock(PR_FALSE) + mCreatorIsBlock(PR_FALSE), + mRootBox(nsIRootBox::GetRootBox(aPresShell)) { mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState(); } @@ -1353,7 +1361,8 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, nsStyleContext* aStyleContext, nsIFrame* aParentFrame, PRBool aCanBePositioned, - PRBool aCanBeFloated) + PRBool aCanBeFloated, + PRBool aIsOutOfFlowPopup) { // The comments in GetGeometricParent regarding root table frames // all apply here, unfortunately. @@ -1383,8 +1392,8 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, } } - if (needPlaceholder) { - NS_ASSERTION(frameItems != &aFrameItems, + if (needPlaceholder || aIsOutOfFlowPopup) { + NS_ASSERTION(frameItems != &aFrameItems || aIsOutOfFlowPopup, "Putting frame in-flow _and_ want a placeholder?"); nsIFrame* placeholderFrame; nsresult rv = @@ -1416,6 +1425,14 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, } #endif + if (NS_UNLIKELY(aIsOutOfFlowPopup)) { + NS_ASSERTION(mRootBox && mRootBox->GetPopupSetFrame(), + "Must have a popup set frame!"); + return mRootBox->GetPopupSetFrame()->AppendFrames(nsGkAtoms::popupList, + aNewFrame); + + } + frameItems->AddChild(aNewFrame); // Now add the special siblings too. @@ -1871,6 +1888,23 @@ GetChildListNameFor(nsIFrame* aChildFrame) listName = nsLayoutAtoms::absoluteList; } else if (NS_STYLE_POSITION_FIXED == disp->mPosition) { listName = nsLayoutAtoms::fixedList; +#ifdef MOZ_XUL + } else if (NS_STYLE_DISPLAY_POPUP == disp->mDisplay) { + // Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set +#ifdef DEBUG + nsIFrame* parent = aChildFrame->GetParent(); + if (parent) { + nsIPopupSetFrame* popupSet; + CallQueryInterface(parent, &popupSet); + NS_ASSERTION(popupSet, "Unexpected parent"); + } +#endif // DEBUG + + // Return here, because the postcondition for this function actually + // fails for this case, since the popups are not in a "real" frame list + // in the popup set. + return nsGkAtoms::popupList; +#endif // MOZ_XUL } else { NS_ASSERTION(aChildFrame->GetStyleDisplay()->IsFloating(), "not a floated frame"); @@ -1882,8 +1916,8 @@ GetChildListNameFor(nsIFrame* aChildFrame) } // Verify that the frame is actually in that child list - NS_ASSERTION(nsFrameList(aChildFrame->GetParent()->GetFirstChild(listName)) - .ContainsFrame(aChildFrame), "not in child list"); + NS_POSTCONDITION(nsFrameList(aChildFrame->GetParent()->GetFirstChild(listName)) + .ContainsFrame(aChildFrame), "not in child list"); return listName; } @@ -6373,30 +6407,41 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState, mayBeScrollable = PR_TRUE; } else if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) { - // This is its own frame that derives from - // box. - isReplaced = PR_TRUE; - newFrame = NS_NewMenuPopupFrame(mPresShell, aStyleContext); - - if (aTag == nsXULAtoms::tooltip) { - if (aContent->AttrValueIs(kNameSpaceID_None, nsXULAtoms::_default, - nsXULAtoms::_true, eIgnoreCase)) { - // Locate the root box and tell it about the tooltip. - nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); - if (rootBox) - rootBox->SetDefaultTooltip(aContent); - } - } - // If a popup is inside a menu, then the menu understands the complex // rules/behavior governing the cascade of multiple menu popups and can handle // having the real popup frame placed under it as a child. // If, however, the parent is *not* a menu frame, then we need to create // a placeholder frame for the popup, and then we add the popup frame to the // root popup set (that manages all such "detached" popups). - nsCOMPtr menuFrame(do_QueryInterface(aParentFrame)); - if (!menuFrame) + nsIMenuFrame* menuFrame; + CallQueryInterface(aParentFrame, &menuFrame); + if (!menuFrame) { + if (!aState.mRootBox || !aState.mRootBox->GetPopupSetFrame()) { + // Just don't create a frame for this popup; we can't do + // anything with it, since there is no root popup set. + *aHaltProcessing = PR_TRUE; + return NS_OK; + } + +#ifdef DEBUG + nsIPopupSetFrame* popupSet; + CallQueryInterface(aState.mRootBox->GetPopupSetFrame(), &popupSet); + NS_ASSERTION(popupSet, "Unexpected return from GetPopupSetFrame()"); +#endif isPopup = PR_TRUE; + } + + // This is its own frame that derives from box. + newFrame = NS_NewMenuPopupFrame(mPresShell, aStyleContext); + + if (aTag == nsXULAtoms::tooltip) { + if (aContent->AttrValueIs(kNameSpaceID_None, nsXULAtoms::_default, + nsXULAtoms::_true, eIgnoreCase)) { + // Tell the root box about the tooltip. + if (aState.mRootBox) + aState.mRootBox->SetDefaultTooltip(aContent); + } + } } else { @@ -6439,8 +6484,15 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState, } // xul does not support absolute positioning - nsIFrame* geometricParent = aParentFrame; - + nsIFrame* geometricParent; + if (isPopup) { + NS_ASSERTION(aState.mRootBox && aState.mRootBox->GetPopupSetFrame(), + "How did we get here?"); + geometricParent = aState.mRootBox->GetPopupSetFrame(); + } else { + geometricParent = aParentFrame; + } + /* nsIFrame* geometricParent = aState.GetGeometricParent(display, aParentFrame); */ @@ -6476,57 +6528,14 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState, } - // If the frame is a popup, then create a placeholder frame -#ifdef MOZ_XUL - if (isPopup) { - nsIFrame* placeholderFrame; - - CreatePlaceholderFrameFor(mPresShell, aState.mPresContext, - aState.mFrameManager, aContent, - newFrame, aStyleContext, aParentFrame, - &placeholderFrame); - - // Locate the root popup set and add ourselves to the popup set's list - // of popup frames. - nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); - PRBool added = PR_FALSE; - if (rootBox) { - nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame(); - NS_ASSERTION(popupSetFrame, "unexpected null pointer"); - if (popupSetFrame) { - nsCOMPtr popupSet(do_QueryInterface(popupSetFrame)); - NS_ASSERTION(popupSet, "unexpected null pointer"); - if (popupSet) { - added = PR_TRUE; - popupSet->AddPopupFrame(newFrame); - } - } - } - - if (added) { - // Add the placeholder frame to the flow - aFrameItems.AddChild(placeholderFrame); - } else { - // Didn't add the popup set frame... Need to clean up and - // just not construct a frame here. - aState.mFrameManager->UnregisterPlaceholderFrame(NS_STATIC_CAST(nsPlaceholderFrame*, placeholderFrame)); - newFrame->Destroy(); - placeholderFrame->Destroy(); - *aHaltProcessing = PR_TRUE; - return NS_OK; - } - } else { -#endif - // Add the new frame to our list of frame items. Note that we - // don't support floating or positioning of XUL frames. - rv = aState.AddChild(topFrame, aFrameItems, display, aContent, - aStyleContext, origParentFrame, PR_FALSE, PR_FALSE); - if (NS_FAILED(rv)) { - return rv; - } -#ifdef MOZ_XUL + // Add the new frame to our list of frame items. Note that we + // don't support floating or positioning of XUL frames. + rv = aState.AddChild(topFrame, aFrameItems, display, aContent, + aStyleContext, origParentFrame, PR_FALSE, PR_FALSE, + isPopup); + if (NS_FAILED(rv)) { + return rv; } -#endif // Process the child content if requested nsFrameItems childItems; @@ -9852,33 +9861,11 @@ DeletingFrameSubtree(nsFrameManager* aFrameManager, for (PRInt32 i = destroyQueue.Count() - 1; i >= 0; --i) { nsIFrame* outOfFlowFrame = NS_STATIC_CAST(nsIFrame*, destroyQueue[i]); -#ifdef MOZ_XUL - const nsStyleDisplay* display = outOfFlowFrame->GetStyleDisplay(); - if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) { - // Locate the root popup set and remove ourselves from the popup set's list - // of popup frames. - nsIRootBox* rootBox = - nsIRootBox::GetRootBox(aFrameManager->GetPresShell()); - NS_ASSERTION(rootBox, "unexpected null pointer"); - if (rootBox) { - nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame(); - NS_ASSERTION(popupSetFrame, "unexpected null pointer"); - if (popupSetFrame) { - nsCOMPtr popupSet(do_QueryInterface(popupSetFrame)); - NS_ASSERTION(popupSet, "unexpected null pointer"); - if (popupSet) - popupSet->RemovePopupFrame(outOfFlowFrame); - } - } - } else -#endif - { - // Ask the out-of-flow's parent to delete the out-of-flow - // frame from the right list. - aFrameManager->RemoveFrame(outOfFlowFrame->GetParent(), - GetChildListNameFor(outOfFlowFrame), - outOfFlowFrame); - } + // Ask the out-of-flow's parent to delete the out-of-flow + // frame from the right list. + aFrameManager->RemoveFrame(outOfFlowFrame->GetParent(), + GetChildListNameFor(outOfFlowFrame), + outOfFlowFrame); } return NS_OK; @@ -10040,36 +10027,14 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, frameManager->UnregisterPlaceholderFrame(placeholderFrame); // Now we remove the out-of-flow frame -#ifdef MOZ_XUL - // Handle XUL popups specially -- they need to be removed from - // the root frame - const nsStyleDisplay* display = childFrame->GetStyleDisplay(); - if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) { - - // Locate the root popup set and remove ourselves from the popup set's list - // of popup frames. - nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell); - if (rootBox) { - nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame(); - if (popupSetFrame) { - nsCOMPtr popupSet(do_QueryInterface(popupSetFrame)); - if (popupSet) - popupSet->RemovePopupFrame(childFrame); - } - } - } else { -#endif - // XXX has to be done first for now: for floats, the block's line list - // contains an array of pointers to the placeholder - we have to - // remove the float first (which gets rid of the lines - // reference to the placeholder and float) and then remove the - // placeholder - rv = frameManager->RemoveFrame(parentFrame, - GetChildListNameFor(childFrame), - childFrame); -#ifdef MOZ_XUL - } -#endif + // XXX has to be done first for now: for floats, the block's line list + // contains an array of pointers to the placeholder - we have to + // remove the float first (which gets rid of the lines + // reference to the placeholder and float) and then remove the + // placeholder + rv = frameManager->RemoveFrame(parentFrame, + GetChildListNameFor(childFrame), + childFrame); // Remove the placeholder frame first (XXX second for now) (so // that it doesn't retain a dangling pointer to memory) diff --git a/mozilla/layout/xul/base/public/nsIPopupSetFrame.h b/mozilla/layout/xul/base/public/nsIPopupSetFrame.h index da255db7684..c82a367fd5f 100644 --- a/mozilla/layout/xul/base/public/nsIPopupSetFrame.h +++ b/mozilla/layout/xul/base/public/nsIPopupSetFrame.h @@ -38,9 +38,10 @@ #ifndef nsIPopupSetFrame_h___ #define nsIPopupSetFrame_h___ -// {E2D804A1-50CA-11d3-BF87-00105A1B0627} +// 043ecc8e-469f-40e1-9569-0529ac0c3039 #define NS_IPOPUPSETFRAME_IID \ -{ 0xe2d804a1, 0x50ca, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } } +{ 0x043ecc8e, 0x469f, 0x40e1, \ + { 0x95, 0x69, 0x05, 0x29, 0xac, 0x0c, 0x30, 0x39 } } class nsIFrame; class nsIContent; @@ -59,9 +60,6 @@ public: const nsString& aPopupAlignment) = 0; NS_IMETHOD HidePopup(nsIFrame* aPopup) = 0; NS_IMETHOD DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain) = 0; - - NS_IMETHOD AddPopupFrame(nsIFrame* aPopup) = 0; - NS_IMETHOD RemovePopupFrame(nsIFrame* aPopup) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIPopupSetFrame, NS_IPOPUPSETFRAME_IID) diff --git a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp index b86c427f736..3c29b2cbc58 100644 --- a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp +++ b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp @@ -149,6 +149,54 @@ nsPopupSetFrame::Init(nsIContent* aContent, return rv; } +NS_IMETHODIMP +nsPopupSetFrame::AppendFrames(nsIAtom* aListName, + nsIFrame* aFrameList) +{ + if (aListName == nsGkAtoms::popupList) { + NS_ASSERTION(!aFrameList->GetNextSibling(), "Append one popup at a time!"); + return AddPopupFrame(aFrameList); + } + + return nsBoxFrame::AppendFrames(aListName, aFrameList); +} + +NS_IMETHODIMP +nsPopupSetFrame::RemoveFrame(nsIAtom* aListName, + nsIFrame* aOldFrame) +{ + if (aListName == nsGkAtoms::popupList) { + return RemovePopupFrame(aOldFrame); + } + + return nsBoxFrame::RemoveFrame(aListName, aOldFrame); +} + +#ifdef DEBUG +NS_IMETHODIMP +nsPopupSetFrame::InsertFrames(nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList) +{ + NS_PRECONDITION(aListName != nsGkAtoms::popupList, + "Shouldn't be inserting popups"); + + return nsBoxFrame::InsertFrames(aListName, aPrevFrame, aFrameList); +} + +NS_IMETHODIMP +nsPopupSetFrame::SetInitialChildList(nsIAtom* aListName, + nsIFrame* aChildList) +{ + NS_PRECONDITION(aListName != nsGkAtoms::popupList, + "Shouldn't be setting initial popup child list"); + + return nsBoxFrame::SetInitialChildList(aListName, aChildList); + +} +#endif + + void nsPopupSetFrame::Destroy() { diff --git a/mozilla/layout/xul/base/src/nsPopupSetFrame.h b/mozilla/layout/xul/base/src/nsPopupSetFrame.h index 68bd16a3d29..bf680cb7dcc 100644 --- a/mozilla/layout/xul/base/src/nsPopupSetFrame.h +++ b/mozilla/layout/xul/base/src/nsPopupSetFrame.h @@ -91,7 +91,19 @@ public: NS_IMETHOD Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow); - + NS_IMETHOD AppendFrames(nsIAtom* aListName, + nsIFrame* aFrameList); + NS_IMETHOD RemoveFrame(nsIAtom* aListName, + nsIFrame* aOldFrame); +#ifdef DEBUG + // Only need these for asserts + NS_IMETHOD InsertFrames(nsIAtom* aListName, + nsIFrame* aPrevFrame, + nsIFrame* aFrameList); + NS_IMETHOD SetInitialChildList(nsIAtom* aListName, + nsIFrame* aChildList); +#endif + // nsIBox NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState); #ifdef DEBUG_LAYOUT @@ -111,9 +123,6 @@ public: NS_IMETHOD HidePopup(nsIFrame* aPopup); NS_IMETHOD DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain); - NS_IMETHOD AddPopupFrame(nsIFrame* aPopup); - NS_IMETHOD RemovePopupFrame(nsIFrame* aPopup); - PRBool OnCreate(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent); PRBool OnDestroy(nsIContent* aPopupContent); PRBool OnCreated(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent); @@ -132,6 +141,9 @@ public: protected: + nsresult AddPopupFrame(nsIFrame* aPopup); + nsresult RemovePopupFrame(nsIFrame* aPopup); + void MarkAsGenerated(nsIContent* aPopupContent); protected: