michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPopupSetFrame.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIContent.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsBoxLayoutState.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsIRootBox.h" michael@0: #include "nsMenuPopupFrame.h" michael@0: michael@0: nsIFrame* michael@0: NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsPopupSetFrame (aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsPopupSetFrame) michael@0: michael@0: void michael@0: nsPopupSetFrame::Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) michael@0: { michael@0: nsBoxFrame::Init(aContent, aParent, aPrevInFlow); michael@0: michael@0: // Normally the root box is our grandparent, but in case of wrapping michael@0: // it can be our great-grandparent. michael@0: nsIRootBox *rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell()); michael@0: if (rootBox) { michael@0: rootBox->SetPopupSetFrame(this); michael@0: } michael@0: } michael@0: michael@0: nsIAtom* michael@0: nsPopupSetFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::popupSetFrame; michael@0: } michael@0: michael@0: nsresult michael@0: nsPopupSetFrame::AppendFrames(ChildListID aListID, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: if (aListID == kPopupList) { michael@0: AddPopupFrameList(aFrameList); michael@0: return NS_OK; michael@0: } michael@0: return nsBoxFrame::AppendFrames(aListID, aFrameList); michael@0: } michael@0: michael@0: nsresult michael@0: nsPopupSetFrame::RemoveFrame(ChildListID aListID, michael@0: nsIFrame* aOldFrame) michael@0: { michael@0: if (aListID == kPopupList) { michael@0: RemovePopupFrame(aOldFrame); michael@0: return NS_OK; michael@0: } michael@0: return nsBoxFrame::RemoveFrame(aListID, aOldFrame); michael@0: } michael@0: michael@0: nsresult michael@0: nsPopupSetFrame::InsertFrames(ChildListID aListID, michael@0: nsIFrame* aPrevFrame, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: if (aListID == kPopupList) { michael@0: AddPopupFrameList(aFrameList); michael@0: return NS_OK; michael@0: } michael@0: return nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList); michael@0: } michael@0: michael@0: nsresult michael@0: nsPopupSetFrame::SetInitialChildList(ChildListID aListID, michael@0: nsFrameList& aChildList) michael@0: { michael@0: if (aListID == kPopupList) { michael@0: NS_ASSERTION(mPopupList.IsEmpty(), michael@0: "SetInitialChildList on non-empty child list"); michael@0: AddPopupFrameList(aChildList); michael@0: return NS_OK; michael@0: } michael@0: return nsBoxFrame::SetInitialChildList(aListID, aChildList); michael@0: } michael@0: michael@0: const nsFrameList& michael@0: nsPopupSetFrame::GetChildList(ChildListID aListID) const michael@0: { michael@0: if (kPopupList == aListID) { michael@0: return mPopupList; michael@0: } michael@0: return nsBoxFrame::GetChildList(aListID); michael@0: } michael@0: michael@0: void michael@0: nsPopupSetFrame::GetChildLists(nsTArray* aLists) const michael@0: { michael@0: nsBoxFrame::GetChildLists(aLists); michael@0: mPopupList.AppendIfNonempty(aLists, kPopupList); michael@0: } michael@0: michael@0: void michael@0: nsPopupSetFrame::DestroyFrom(nsIFrame* aDestructRoot) michael@0: { michael@0: mPopupList.DestroyFramesFrom(aDestructRoot); michael@0: michael@0: // Normally the root box is our grandparent, but in case of wrapping michael@0: // it can be our great-grandparent. michael@0: nsIRootBox *rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell()); michael@0: if (rootBox) { michael@0: rootBox->SetPopupSetFrame(nullptr); michael@0: } michael@0: michael@0: nsBoxFrame::DestroyFrom(aDestructRoot); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState) michael@0: { michael@0: // lay us out michael@0: nsresult rv = nsBoxFrame::DoLayout(aState); michael@0: michael@0: // lay out all of our currently open popups. michael@0: for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) { michael@0: nsMenuPopupFrame* popupChild = static_cast(e.get()); michael@0: popupChild->LayoutPopup(aState, nullptr, nullptr, false); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsPopupSetFrame::RemovePopupFrame(nsIFrame* aPopup) michael@0: { michael@0: NS_PRECONDITION((aPopup->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && michael@0: aPopup->GetType() == nsGkAtoms::menuPopupFrame, michael@0: "removing wrong type of frame in popupset's ::popupList"); michael@0: michael@0: mPopupList.DestroyFrame(aPopup); michael@0: } michael@0: michael@0: void michael@0: nsPopupSetFrame::AddPopupFrameList(nsFrameList& aPopupFrameList) michael@0: { michael@0: #ifdef DEBUG michael@0: for (nsFrameList::Enumerator e(aPopupFrameList); !e.AtEnd(); e.Next()) { michael@0: NS_ASSERTION((e.get()->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && michael@0: e.get()->GetType() == nsGkAtoms::menuPopupFrame, michael@0: "adding wrong type of frame in popupset's ::popupList"); michael@0: } michael@0: #endif michael@0: mPopupList.InsertFrames(nullptr, nullptr, aPopupFrameList); michael@0: }