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
This commit is contained in:
bzbarsky%mit.edu
2006-08-29 22:20:41 +00:00
parent 4b00e37b9d
commit 2cdb5cc2b9
4 changed files with 166 additions and 143 deletions

View File

@@ -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<nsIMenuFrame> 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<nsIPopupSetFrame> 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<nsIPopupSetFrame> 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<nsIPopupSetFrame> 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)

View File

@@ -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)

View File

@@ -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()
{

View File

@@ -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: