gecko-dev/layout/xul/nsPopupSetFrame.cpp

161 lines
4.3 KiB
C++

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