diff options
Diffstat (limited to 'layout/xul/nsRootBoxFrame.cpp')
-rw-r--r-- | layout/xul/nsRootBoxFrame.cpp | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/layout/xul/nsRootBoxFrame.cpp b/layout/xul/nsRootBoxFrame.cpp new file mode 100644 index 0000000000..fe41dce527 --- /dev/null +++ b/layout/xul/nsRootBoxFrame.cpp @@ -0,0 +1,291 @@ +/* -*- 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 "nsHTMLParts.h" +#include "nsStyleConsts.h" +#include "nsGkAtoms.h" +#include "nsIPresShell.h" +#include "nsBoxFrame.h" +#include "nsStackLayout.h" +#include "nsIRootBox.h" +#include "nsIContent.h" +#include "nsXULTooltipListener.h" +#include "nsFrameManager.h" +#include "mozilla/BasicEvents.h" + +using namespace mozilla; + +// Interface IDs + +//#define DEBUG_REFLOW + +// static +nsIRootBox* +nsIRootBox::GetRootBox(nsIPresShell* aShell) +{ + if (!aShell) { + return nullptr; + } + nsIFrame* rootFrame = aShell->FrameManager()->GetRootFrame(); + if (!rootFrame) { + return nullptr; + } + + if (rootFrame) { + rootFrame = rootFrame->PrincipalChildList().FirstChild(); + } + + nsIRootBox* rootBox = do_QueryFrame(rootFrame); + return rootBox; +} + +class nsRootBoxFrame : public nsBoxFrame, public nsIRootBox { +public: + + friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + + explicit nsRootBoxFrame(nsStyleContext* aContext); + + NS_DECL_QUERYFRAME + NS_DECL_FRAMEARENA_HELPERS + + virtual nsPopupSetFrame* GetPopupSetFrame() override; + virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) override; + virtual nsIContent* GetDefaultTooltip() override; + virtual void SetDefaultTooltip(nsIContent* aTooltip) override; + virtual nsresult AddTooltipSupport(nsIContent* aNode) override; + virtual nsresult RemoveTooltipSupport(nsIContent* aNode) override; + + virtual void AppendFrames(ChildListID aListID, + nsFrameList& aFrameList) override; + virtual void InsertFrames(ChildListID aListID, + nsIFrame* aPrevFrame, + nsFrameList& aFrameList) override; + virtual void RemoveFrame(ChildListID aListID, + nsIFrame* aOldFrame) override; + + virtual void Reflow(nsPresContext* aPresContext, + ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + virtual nsresult HandleEvent(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) override; + + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) override; + + /** + * Get the "type" of the frame + * + * @see nsGkAtoms::rootFrame + */ + virtual nsIAtom* GetType() const override; + + virtual bool IsFrameOfType(uint32_t aFlags) const override + { + // Override bogus IsFrameOfType in nsBoxFrame. + if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced)) + return false; + return nsBoxFrame::IsFrameOfType(aFlags); + } + +#ifdef DEBUG_FRAME_DUMP + virtual nsresult GetFrameName(nsAString& aResult) const override; +#endif + + nsPopupSetFrame* mPopupSetFrame; + +protected: + nsIContent* mDefaultTooltip; +}; + +//---------------------------------------------------------------------- + +nsContainerFrame* +NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) nsRootBoxFrame(aContext); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsRootBoxFrame) + +nsRootBoxFrame::nsRootBoxFrame(nsStyleContext* aContext): + nsBoxFrame(aContext, true) +{ + mPopupSetFrame = nullptr; + + nsCOMPtr<nsBoxLayout> layout; + NS_NewStackLayout(layout); + SetXULLayoutManager(layout); +} + +void +nsRootBoxFrame::AppendFrames(ChildListID aListID, + nsFrameList& aFrameList) +{ + MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list ID"); + MOZ_ASSERT(mFrames.IsEmpty(), "already have a child frame"); + nsBoxFrame::AppendFrames(aListID, aFrameList); +} + +void +nsRootBoxFrame::InsertFrames(ChildListID aListID, + nsIFrame* aPrevFrame, + nsFrameList& aFrameList) +{ + // Because we only support a single child frame inserting is the same + // as appending. + MOZ_ASSERT(!aPrevFrame, "unexpected previous sibling frame"); + AppendFrames(aListID, aFrameList); +} + +void +nsRootBoxFrame::RemoveFrame(ChildListID aListID, + nsIFrame* aOldFrame) +{ + NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID"); + if (aOldFrame == mFrames.FirstChild()) { + nsBoxFrame::RemoveFrame(aListID, aOldFrame); + } else { + MOZ_CRASH("unknown aOldFrame"); + } +} + +#ifdef DEBUG_REFLOW +int32_t gReflows = 0; +#endif + +void +nsRootBoxFrame::Reflow(nsPresContext* aPresContext, + ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) +{ + DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame"); + +#ifdef DEBUG_REFLOW + gReflows++; + printf("----Reflow %d----\n", gReflows); +#endif + return nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus); +} + +void +nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + if (mContent && mContent->GetProperty(nsGkAtoms::DisplayPortMargins)) { + // The XUL document's root element may have displayport margins set in + // ChromeProcessController::InitializeRoot, and we should to supply the + // base rect. + nsRect displayPortBase = aDirtyRect.Intersect(nsRect(nsPoint(0, 0), GetSize())); + nsLayoutUtils::SetDisplayPortBase(mContent, displayPortBase); + } + + // root boxes don't need a debug border/outline or a selection overlay... + // They *may* have a background propagated to them, so force creation + // of a background display list element. + DisplayBorderBackgroundOutline(aBuilder, aLists, true); + + BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); +} + +nsresult +nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) +{ + NS_ENSURE_ARG_POINTER(aEventStatus); + if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { + return NS_OK; + } + + if (aEvent->mMessage == eMouseUp) { + nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); + } + + return NS_OK; +} + +// REVIEW: The override here was doing nothing since nsBoxFrame is our +// parent class +nsIAtom* +nsRootBoxFrame::GetType() const +{ + return nsGkAtoms::rootFrame; +} + +nsPopupSetFrame* +nsRootBoxFrame::GetPopupSetFrame() +{ + return mPopupSetFrame; +} + +void +nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet) +{ + // 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(nullptr)|, 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."); + } +} + +nsIContent* +nsRootBoxFrame::GetDefaultTooltip() +{ + return mDefaultTooltip; +} + +void +nsRootBoxFrame::SetDefaultTooltip(nsIContent* aTooltip) +{ + mDefaultTooltip = aTooltip; +} + +nsresult +nsRootBoxFrame::AddTooltipSupport(nsIContent* aNode) +{ + NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); + + nsXULTooltipListener *listener = nsXULTooltipListener::GetInstance(); + if (!listener) + return NS_ERROR_OUT_OF_MEMORY; + + return listener->AddTooltipSupport(aNode); +} + +nsresult +nsRootBoxFrame::RemoveTooltipSupport(nsIContent* aNode) +{ + // XXjh yuck, I'll have to implement a way to get at + // the tooltip listener for a given node to make + // this work. Not crucial, we aren't removing + // tooltips from any nodes in the app just yet. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_QUERYFRAME_HEAD(nsRootBoxFrame) + NS_QUERYFRAME_ENTRY(nsIRootBox) +NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) + +#ifdef DEBUG_FRAME_DUMP +nsresult +nsRootBoxFrame::GetFrameName(nsAString& aResult) const +{ + return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult); +} +#endif |