Make PopupSet registration on the root box frame done by the popupset and add unregistration when the popupset goes away to fix crashes from dangling pointers. b=156719 (and 136513) r=bryner sr=kin

This commit is contained in:
dbaron%fas.harvard.edu 2002-08-19 18:29:29 +00:00
parent 78007eba43
commit d765859c85
4 changed files with 32 additions and 22 deletions

View File

@ -5463,16 +5463,6 @@ nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell,
isReplaced = PR_TRUE;
rv = NS_NewPopupSetFrame(aPresShell, &newFrame);
((nsPopupSetFrame*) newFrame)->SetFrameConstructor(this);
// Locate the root frame and tell it about the popupgroup.
nsIFrame* rootFrame;
aState.mFrameManager->GetRootFrame(&rootFrame);
if (rootFrame)
rootFrame->FirstChild(aPresContext, nsnull, &rootFrame);
nsCOMPtr<nsIRootBox> rootBox(do_QueryInterface(rootFrame));
if (rootBox)
rootBox->SetPopupSetFrame(newFrame);
}
else if (aTag == nsXULAtoms::scrollbox) {
rv = NS_NewScrollBoxFrame(aPresShell, &newFrame);

View File

@ -5463,16 +5463,6 @@ nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell,
isReplaced = PR_TRUE;
rv = NS_NewPopupSetFrame(aPresShell, &newFrame);
((nsPopupSetFrame*) newFrame)->SetFrameConstructor(this);
// Locate the root frame and tell it about the popupgroup.
nsIFrame* rootFrame;
aState.mFrameManager->GetRootFrame(&rootFrame);
if (rootFrame)
rootFrame->FirstChild(aPresContext, nsnull, &rootFrame);
nsCOMPtr<nsIRootBox> rootBox(do_QueryInterface(rootFrame));
if (rootBox)
rootBox->SetPopupSetFrame(newFrame);
}
else if (aTag == nsXULAtoms::scrollbox) {
rv = NS_NewScrollBoxFrame(aPresShell, &newFrame);

View File

@ -67,6 +67,7 @@
#include "nsIScrollableFrame.h"
#include "nsCSSFrameConstructor.h"
#include "nsGUIEvent.h"
#include "nsIRootBox.h"
#define NS_MENU_POPUP_LIST_INDEX 0
@ -158,6 +159,16 @@ nsPopupSetFrame::Init(nsIPresContext* aPresContext,
{
mPresContext = aPresContext; // Don't addref it. Our lifetime is shorter.
nsresult rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
nsIFrame *grandParent;
aParent->GetParent(&grandParent);
nsIRootBox *rootBox;
nsresult res = CallQueryInterface(grandParent, &rootBox);
NS_ASSERTION(NS_SUCCEEDED(res), "grandparent should be root box");
if (NS_SUCCEEDED(res)) {
rootBox->SetPopupSetFrame(this);
}
return rv;
}
@ -177,6 +188,15 @@ nsPopupSetFrame::Destroy(nsIPresContext* aPresContext)
}
}
nsIFrame *grandParent;
mParent->GetParent(&grandParent);
nsIRootBox *rootBox;
nsresult res = CallQueryInterface(grandParent, &rootBox);
NS_ASSERTION(NS_SUCCEEDED(res), "grandparent should be root box");
if (NS_SUCCEEDED(res)) {
rootBox->SetPopupSetFrame(nsnull);
}
return nsBoxFrame::Destroy(aPresContext);
}

View File

@ -289,9 +289,19 @@ nsRootBoxFrame::GetPopupSetFrame(nsIFrame** aResult)
NS_IMETHODIMP
nsRootBoxFrame::SetPopupSetFrame(nsIFrame* aPopupSet)
{
NS_ASSERTION(!mPopupSetFrame, "Popup set is already defined! Only 1 allowed.");
if (!mPopupSetFrame)
// Under normal conditions this should only be called once. However,
// if something triggers ReconstructDocElementHierarchy, we will
// destroy this frame's child (the nsDocElementBoxFrame), but not this
// frame. This will cause the popupset to remove itself by calling
// |SetPopupSetFrame(nsnull)|, and then we'll be able to accept a new
// popupset. Since the anonymous content is associated with the
// nsDocElementBoxFrame, we'll get a new popupset when the new doc
// element box frame is created.
if (!mPopupSetFrame || !aPopupSet) {
mPopupSetFrame = aPopupSet;
} else {
NS_NOTREACHED("Popup set is already defined! Only 1 allowed.");
}
return NS_OK;
}