Bug 728913 - Remove the nsMenuFrame::mPopupFrame member and store it in a nsFrameList* frame property instead (as needed). r=bz

This commit is contained in:
Mats Palmgren 2012-03-08 02:57:37 +01:00
Родитель c1f99b666b
Коммит d1874aa971
3 изменённых файлов: 121 добавлений и 56 удалений

Просмотреть файл

@ -61,7 +61,7 @@ class nsBoxLayoutState;
#define NS_STATE_CURRENTLY_IN_DEBUG NS_FRAME_STATE_BIT(25)
//#define NS_STATE_SET_TO_DEBUG NS_FRAME_STATE_BIT(26) moved to nsBox.h
//#define NS_STATE_DEBUG_WAS_SET NS_FRAME_STATE_BIT(27) moved to nsBox.h
// NS_FRAME_STATE_BIT(28) not used anymore
#define NS_STATE_MENU_HAS_POPUP_LIST NS_FRAME_STATE_BIT(28) /* used on nsMenuFrame */
#define NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK NS_FRAME_STATE_BIT(29)
#define NS_STATE_EQUAL_SIZE NS_FRAME_STATE_BIT(30)
//#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31) moved to nsIFrame.h

Просмотреть файл

@ -87,6 +87,13 @@ using namespace mozilla;
#define NSCONTEXTMENUISMOUSEUP 1
#endif
static void
AssertNotCalled(void* aPropertyValue)
{
NS_ERROR("popup list should never be destroyed by the FramePropertyTable");
}
NS_DECLARE_FRAME_PROPERTY(PopupListProperty, AssertNotCalled)
static PRInt32 gEatMouseMove = false;
const PRInt32 kBlinkDelay = 67; // milliseconds
@ -207,9 +214,6 @@ NS_QUERYFRAME_HEAD(nsMenuFrame)
NS_QUERYFRAME_ENTRY(nsMenuFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
//
// nsMenuFrame cntr
//
nsMenuFrame::nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext):
nsBoxFrame(aShell, aContext),
mIsMenu(false),
@ -217,11 +221,9 @@ nsMenuFrame::nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext):
mIgnoreAccelTextChange(false),
mType(eMenuType_Normal),
mMenuParent(nsnull),
mPopupFrame(nsnull),
mBlinkState(0)
{
} // cntr
}
void
nsMenuFrame::SetParent(nsIFrame* aParent)
@ -302,7 +304,8 @@ nsFrameList
nsMenuFrame::GetChildList(ChildListID aListID) const
{
if (kPopupList == aListID) {
return nsFrameList(mPopupFrame, mPopupFrame);
nsFrameList* list = GetPopupList();
return list ? *list : nsFrameList::EmptyList();
}
return nsBoxFrame::GetChildList(aListID);
}
@ -311,8 +314,44 @@ void
nsMenuFrame::GetChildLists(nsTArray<ChildList>* aLists) const
{
nsBoxFrame::GetChildLists(aLists);
nsFrameList popupList(mPopupFrame, mPopupFrame);
popupList.AppendIfNonempty(aLists, kPopupList);
nsFrameList* list = GetPopupList();
if (list) {
list->AppendIfNonempty(aLists, kPopupList);
}
}
nsMenuPopupFrame*
nsMenuFrame::GetPopup()
{
nsFrameList* popupList = GetPopupList();
return popupList ? static_cast<nsMenuPopupFrame*>(popupList->FirstChild()) :
nsnull;
}
nsFrameList*
nsMenuFrame::GetPopupList() const
{
if (!HasPopup()) {
return nsnull;
}
nsFrameList* prop =
static_cast<nsFrameList*>(Properties().Get(PopupListProperty()));
NS_ASSERTION(prop && prop->GetLength() == 1 &&
prop->FirstChild()->GetType() == nsGkAtoms::menuPopupFrame,
"popup list should have exactly one nsMenuPopupFrame");
return prop;
}
void
nsMenuFrame::DestroyPopupList()
{
NS_ASSERTION(HasPopup(), "huh?");
nsFrameList* prop =
static_cast<nsFrameList*>(Properties().Remove(PopupListProperty()));
NS_ASSERTION(prop && prop->IsEmpty(),
"popup list must exist and be empty when destroying");
RemoveStateBits(NS_STATE_MENU_HAS_POPUP_LIST);
delete prop;
}
void
@ -320,9 +359,12 @@ nsMenuFrame::SetPopupFrame(nsFrameList& aFrameList)
{
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
if (e.get()->GetType() == nsGkAtoms::menuPopupFrame) {
// Remove this frame from the list and set it as mPopupFrame
mPopupFrame = (nsMenuPopupFrame *)e.get();
aFrameList.RemoveFrame(e.get());
// Remove the frame from the list and store it in a nsFrameList* property.
nsIFrame* popupFrame = e.get();
aFrameList.RemoveFrame(popupFrame);
nsFrameList* popupList = new nsFrameList(popupFrame, popupFrame);
Properties().Set(PopupListProperty(), popupList);
AddStateBits(NS_STATE_MENU_HAS_POPUP_LIST);
break;
}
}
@ -332,7 +374,7 @@ NS_IMETHODIMP
nsMenuFrame::SetInitialChildList(ChildListID aListID,
nsFrameList& aChildList)
{
NS_ASSERTION(!mPopupFrame, "already have a popup frame set");
NS_ASSERTION(!HasPopup(), "SetInitialChildList called twice?");
if (aListID == kPrincipalList || aListID == kPopupList) {
SetPopupFrame(aChildList);
}
@ -365,8 +407,11 @@ nsMenuFrame::DestroyFrom(nsIFrame* aDestructRoot)
mMenuParent->CurrentMenuIsBeingDestroyed();
}
if (mPopupFrame)
mPopupFrame->DestroyFrom(aDestructRoot);
nsFrameList* popupList = GetPopupList();
if (popupList) {
popupList->DestroyFramesFrom(aDestructRoot);
DestroyPopupList();
}
nsBoxFrame::DestroyFrom(aDestructRoot);
}
@ -675,8 +720,8 @@ nsMenuFrame::CloseMenu(bool aDeselectMenu)
// Close the menu asynchronously
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mPopupFrame)
pm->HidePopup(mPopupFrame->GetContent(), false, aDeselectMenu, true);
if (pm && HasPopup())
pm->HidePopup(GetPopup()->GetContent(), false, aDeselectMenu, true);
}
bool
@ -713,9 +758,10 @@ nsMenuFrame::DoLayout(nsBoxLayoutState& aState)
// lay us out
nsresult rv = nsBoxFrame::DoLayout(aState);
if (mPopupFrame) {
nsMenuPopupFrame* popupFrame = GetPopup();
if (popupFrame) {
bool sizeToPopup = IsSizedToPopup(mContent, false);
mPopupFrame->LayoutPopup(aState, this, sizeToPopup);
popupFrame->LayoutPopup(aState, this, sizeToPopup);
}
return rv;
@ -733,8 +779,9 @@ nsMenuFrame::SetDebug(nsBoxLayoutState& aState, bool aDebug)
if (debugChanged)
{
nsBoxFrame::SetDebug(aState, aDebug);
if (mPopupFrame)
SetDebug(aState, mPopupFrame, aDebug);
nsMenuPopupFrame* popupFrame = GetPopup();
if (popupFrame)
SetDebug(aState, popupFrame, aDebug);
}
return NS_OK;
@ -797,7 +844,8 @@ nsMenuFrame::Enter(nsGUIEvent *aEvent)
bool
nsMenuFrame::IsOpen()
{
return mPopupFrame && mPopupFrame->IsOpen();
nsMenuPopupFrame* popupFrame = GetPopup();
return popupFrame && popupFrame->IsOpen();
}
bool
@ -1248,21 +1296,15 @@ NS_IMETHODIMP
nsMenuFrame::RemoveFrame(ChildListID aListID,
nsIFrame* aOldFrame)
{
nsresult rv = NS_OK;
if (mPopupFrame == aOldFrame) {
// Go ahead and remove this frame.
mPopupFrame->Destroy();
mPopupFrame = nsnull;
nsFrameList* popupList = GetPopupList();
if (popupList && popupList->DestroyFrameIfPresent(aOldFrame)) {
DestroyPopupList();
PresContext()->PresShell()->
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
rv = NS_OK;
} else {
rv = nsBoxFrame::RemoveFrame(aListID, aOldFrame);
return NS_OK;
}
return rv;
return nsBoxFrame::RemoveFrame(aListID, aOldFrame);
}
NS_IMETHODIMP
@ -1270,9 +1312,9 @@ nsMenuFrame::InsertFrames(ChildListID aListID,
nsIFrame* aPrevFrame,
nsFrameList& aFrameList)
{
if (!mPopupFrame && (aListID == kPrincipalList || aListID == kPopupList)) {
if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
SetPopupFrame(aFrameList);
if (mPopupFrame) {
if (HasPopup()) {
#ifdef DEBUG_LAYOUT
nsBoxLayoutState state(PresContext());
SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
@ -1287,7 +1329,7 @@ nsMenuFrame::InsertFrames(ChildListID aListID,
if (aFrameList.IsEmpty())
return NS_OK;
if (NS_UNLIKELY(aPrevFrame == mPopupFrame)) {
if (NS_UNLIKELY(aPrevFrame && aPrevFrame == GetPopup())) {
aPrevFrame = nsnull;
}
@ -1298,9 +1340,9 @@ NS_IMETHODIMP
nsMenuFrame::AppendFrames(ChildListID aListID,
nsFrameList& aFrameList)
{
if (!mPopupFrame && (aListID == kPrincipalList || aListID == kPopupList)) {
if (!HasPopup() && (aListID == kPrincipalList || aListID == kPopupList)) {
SetPopupFrame(aFrameList);
if (mPopupFrame) {
if (HasPopup()) {
#ifdef DEBUG_LAYOUT
nsBoxLayoutState state(PresContext());
@ -1326,9 +1368,10 @@ nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize)
nsSize tmpSize(-1, 0);
nsIBox::AddCSSPrefSize(this, tmpSize, widthSet, heightSet);
if (!widthSet && GetFlex(aState) == 0) {
if (!mPopupFrame)
nsMenuPopupFrame* popupFrame = GetPopup();
if (!popupFrame)
return false;
tmpSize = mPopupFrame->GetPrefSize(aState);
tmpSize = popupFrame->GetPrefSize(aState);
// Produce a size such that:
// (1) the menu and its popup can be the same width
@ -1340,7 +1383,7 @@ nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize)
GetBorderAndPadding(borderPadding);
// if there is a scroll frame, add the desired width of the scrollbar as well
nsIScrollableFrame* scrollFrame = do_QueryFrame(mPopupFrame->GetFirstPrincipalChild());
nsIScrollableFrame* scrollFrame = do_QueryFrame(popupFrame->GetFirstPrincipalChild());
nscoord scrollbarWidth = 0;
if (scrollFrame) {
scrollbarWidth =
@ -1380,10 +1423,11 @@ nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState)
NS_IMETHODIMP
nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
{
if (!mPopupFrame)
nsMenuPopupFrame* popupFrame = GetPopup();
if (!popupFrame)
return NS_ERROR_FAILURE;
nsMenuFrame* menuFrame = mPopupFrame->GetCurrentMenuItem();
nsMenuFrame* menuFrame = popupFrame->GetCurrentMenuItem();
if (!menuFrame) {
*aResult = nsnull;
}
@ -1399,12 +1443,13 @@ nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
NS_IMETHODIMP
nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
{
if (!mPopupFrame)
nsMenuPopupFrame* popupFrame = GetPopup();
if (!popupFrame)
return NS_ERROR_FAILURE;
if (!aChild) {
// Remove the current selection
mPopupFrame->ChangeMenuItem(nsnull, false);
popupFrame->ChangeMenuItem(nsnull, false);
return NS_OK;
}
@ -1412,17 +1457,18 @@ nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
nsIFrame* kid = child->GetPrimaryFrame();
if (kid && kid->GetType() == nsGkAtoms::menuFrame)
mPopupFrame->ChangeMenuItem(static_cast<nsMenuFrame *>(kid), false);
popupFrame->ChangeMenuItem(static_cast<nsMenuFrame *>(kid), false);
return NS_OK;
}
nsIScrollableFrame* nsMenuFrame::GetScrollTargetFrame()
{
if (!mPopupFrame)
nsMenuPopupFrame* popupFrame = GetPopup();
if (!popupFrame)
return nsnull;
nsIFrame* childFrame = mPopupFrame->GetFirstPrincipalChild();
nsIFrame* childFrame = popupFrame->GetFirstPrincipalChild();
if (childFrame)
return mPopupFrame->GetScrollFrame(childFrame);
return popupFrame->GetScrollFrame(childFrame);
return nsnull;
}

Просмотреть файл

@ -185,7 +185,16 @@ public:
virtual nsMenuParent *GetMenuParent() { return mMenuParent; }
const nsAString& GetRadioGroupName() { return mGroupName; }
nsMenuType GetMenuType() { return mType; }
nsMenuPopupFrame* GetPopup() { return mPopupFrame; }
nsMenuPopupFrame* GetPopup();
/**
* @return true if this frame has a popup child frame.
*/
bool HasPopup() const
{
return (GetStateBits() & NS_STATE_MENU_HAS_POPUP_LIST) != 0;
}
// nsMenuFrame methods
@ -226,10 +235,23 @@ protected:
friend class nsASyncMenuInitialization;
friend class nsMenuAttributeChangedEvent;
// initialize mPopupFrame to the first popup frame within
// aChildList. Removes the popup, if any, from aChildList.
/**
* Initialize the popup list to the first popup frame within
* aChildList. Removes the popup, if any, from aChildList.
*/
void SetPopupFrame(nsFrameList& aChildList);
/**
* Get the popup frame list from the frame property.
* @return the property value if it exists, nsnull otherwise.
*/
nsFrameList* GetPopupList() const;
/**
* Destroy the popup list property. The list must exist and be empty.
*/
void DestroyPopupList();
// set mMenuParent to the nearest enclosing menu bar or menupopup frame of
// aParent (or aParent itself). This is called when initializing the frame,
// so aParent should be the expected parent of this frame.
@ -275,9 +297,6 @@ protected:
nsMenuParent* mMenuParent; // Our parent menu.
// the popup for this menu, owned
nsMenuPopupFrame* mPopupFrame;
// Reference to the mediator which wraps this frame.
nsRefPtr<nsMenuTimerMediator> mTimerMediator;