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 "nsHTMLParts.h" michael@0: #include "nsStyleConsts.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsBoxFrame.h" michael@0: #include "nsStackLayout.h" michael@0: #include "nsIRootBox.h" michael@0: #include "nsIContent.h" michael@0: #include "nsXULTooltipListener.h" michael@0: #include "nsFrameManager.h" michael@0: #include "mozilla/BasicEvents.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // Interface IDs michael@0: michael@0: //#define DEBUG_REFLOW michael@0: michael@0: // static michael@0: nsIRootBox* michael@0: nsIRootBox::GetRootBox(nsIPresShell* aShell) michael@0: { michael@0: if (!aShell) { michael@0: return nullptr; michael@0: } michael@0: nsIFrame* rootFrame = aShell->FrameManager()->GetRootFrame(); michael@0: if (!rootFrame) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (rootFrame) { michael@0: rootFrame = rootFrame->GetFirstPrincipalChild(); michael@0: } michael@0: michael@0: nsIRootBox* rootBox = do_QueryFrame(rootFrame); michael@0: return rootBox; michael@0: } michael@0: michael@0: class nsRootBoxFrame : public nsBoxFrame, public nsIRootBox { michael@0: public: michael@0: michael@0: friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); michael@0: michael@0: nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext *aContext); michael@0: michael@0: NS_DECL_QUERYFRAME michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: michael@0: virtual nsPopupSetFrame* GetPopupSetFrame() MOZ_OVERRIDE; michael@0: virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) MOZ_OVERRIDE; michael@0: virtual nsIContent* GetDefaultTooltip() MOZ_OVERRIDE; michael@0: virtual void SetDefaultTooltip(nsIContent* aTooltip) MOZ_OVERRIDE; michael@0: virtual nsresult AddTooltipSupport(nsIContent* aNode) MOZ_OVERRIDE; michael@0: virtual nsresult RemoveTooltipSupport(nsIContent* aNode) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult AppendFrames(ChildListID aListID, michael@0: nsFrameList& aFrameList) MOZ_OVERRIDE; michael@0: virtual nsresult InsertFrames(ChildListID aListID, michael@0: nsIFrame* aPrevFrame, michael@0: nsFrameList& aFrameList) MOZ_OVERRIDE; michael@0: virtual nsresult RemoveFrame(ChildListID aListID, michael@0: nsIFrame* aOldFrame) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) MOZ_OVERRIDE; michael@0: virtual nsresult HandleEvent(nsPresContext* aPresContext, michael@0: WidgetGUIEvent* aEvent, michael@0: nsEventStatus* aEventStatus) MOZ_OVERRIDE; michael@0: michael@0: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Get the "type" of the frame michael@0: * michael@0: * @see nsGkAtoms::rootFrame michael@0: */ michael@0: virtual nsIAtom* GetType() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE michael@0: { michael@0: // Override bogus IsFrameOfType in nsBoxFrame. michael@0: if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced)) michael@0: return false; michael@0: return nsBoxFrame::IsFrameOfType(aFlags); michael@0: } michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: nsPopupSetFrame* mPopupSetFrame; michael@0: michael@0: protected: michael@0: nsIContent* mDefaultTooltip; michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: nsIFrame* michael@0: NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsRootBoxFrame (aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsRootBoxFrame) michael@0: michael@0: nsRootBoxFrame::nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext): michael@0: nsBoxFrame(aShell, aContext, true) michael@0: { michael@0: mPopupSetFrame = nullptr; michael@0: michael@0: nsCOMPtr layout; michael@0: NS_NewStackLayout(aShell, layout); michael@0: SetLayoutManager(layout); michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::AppendFrames(ChildListID aListID, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: nsresult rv; michael@0: michael@0: NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID"); michael@0: NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame"); michael@0: if (aListID != kPrincipalList) { michael@0: // We only support the principal child list. michael@0: rv = NS_ERROR_INVALID_ARG; michael@0: } else if (!mFrames.IsEmpty()) { michael@0: // We only allow a single child frame. michael@0: rv = NS_ERROR_FAILURE; michael@0: } else { michael@0: rv = nsBoxFrame::AppendFrames(aListID, aFrameList); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::InsertFrames(ChildListID aListID, michael@0: nsIFrame* aPrevFrame, michael@0: nsFrameList& aFrameList) michael@0: { michael@0: nsresult rv; michael@0: michael@0: // Because we only support a single child frame inserting is the same michael@0: // as appending. michael@0: NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame"); michael@0: if (aPrevFrame) { michael@0: rv = NS_ERROR_UNEXPECTED; michael@0: } else { michael@0: rv = AppendFrames(aListID, aFrameList); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::RemoveFrame(ChildListID aListID, michael@0: nsIFrame* aOldFrame) michael@0: { michael@0: nsresult rv; michael@0: michael@0: NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID"); michael@0: if (aListID != kPrincipalList) { michael@0: // We only support the principal child list. michael@0: rv = NS_ERROR_INVALID_ARG; michael@0: } else if (aOldFrame == mFrames.FirstChild()) { michael@0: rv = nsBoxFrame::RemoveFrame(aListID, aOldFrame); michael@0: } else { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: #ifdef DEBUG_REFLOW michael@0: int32_t gReflows = 0; michael@0: #endif michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame"); michael@0: michael@0: #ifdef DEBUG_REFLOW michael@0: gReflows++; michael@0: printf("----Reflow %d----\n", gReflows); michael@0: #endif michael@0: return nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); michael@0: } michael@0: michael@0: void michael@0: nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // root boxes don't need a debug border/outline or a selection overlay... michael@0: // They *may* have a background propagated to them, so force creation michael@0: // of a background display list element. michael@0: DisplayBorderBackgroundOutline(aBuilder, aLists, true); michael@0: michael@0: BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext, michael@0: WidgetGUIEvent* aEvent, michael@0: nsEventStatus* aEventStatus) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEventStatus); michael@0: if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aEvent->message == NS_MOUSE_BUTTON_UP) { michael@0: nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // REVIEW: The override here was doing nothing since nsBoxFrame is our michael@0: // parent class michael@0: nsIAtom* michael@0: nsRootBoxFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::rootFrame; michael@0: } michael@0: michael@0: nsPopupSetFrame* michael@0: nsRootBoxFrame::GetPopupSetFrame() michael@0: { michael@0: return mPopupSetFrame; michael@0: } michael@0: michael@0: void michael@0: nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet) michael@0: { michael@0: // Under normal conditions this should only be called once. However, michael@0: // if something triggers ReconstructDocElementHierarchy, we will michael@0: // destroy this frame's child (the nsDocElementBoxFrame), but not this michael@0: // frame. This will cause the popupset to remove itself by calling michael@0: // |SetPopupSetFrame(nullptr)|, and then we'll be able to accept a new michael@0: // popupset. Since the anonymous content is associated with the michael@0: // nsDocElementBoxFrame, we'll get a new popupset when the new doc michael@0: // element box frame is created. michael@0: if (!mPopupSetFrame || !aPopupSet) { michael@0: mPopupSetFrame = aPopupSet; michael@0: } else { michael@0: NS_NOTREACHED("Popup set is already defined! Only 1 allowed."); michael@0: } michael@0: } michael@0: michael@0: nsIContent* michael@0: nsRootBoxFrame::GetDefaultTooltip() michael@0: { michael@0: return mDefaultTooltip; michael@0: } michael@0: michael@0: void michael@0: nsRootBoxFrame::SetDefaultTooltip(nsIContent* aTooltip) michael@0: { michael@0: mDefaultTooltip = aTooltip; michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::AddTooltipSupport(nsIContent* aNode) michael@0: { michael@0: NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); michael@0: michael@0: nsXULTooltipListener *listener = nsXULTooltipListener::GetInstance(); michael@0: if (!listener) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return listener->AddTooltipSupport(aNode); michael@0: } michael@0: michael@0: nsresult michael@0: nsRootBoxFrame::RemoveTooltipSupport(nsIContent* aNode) michael@0: { michael@0: // XXjh yuck, I'll have to implement a way to get at michael@0: // the tooltip listener for a given node to make michael@0: // this work. Not crucial, we aren't removing michael@0: // tooltips from any nodes in the app just yet. michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_QUERYFRAME_HEAD(nsRootBoxFrame) michael@0: NS_QUERYFRAME_ENTRY(nsIRootBox) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: nsresult michael@0: nsRootBoxFrame::GetFrameName(nsAString& aResult) const michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult); michael@0: } michael@0: #endif