/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsHTMLParts.h" #include "nsIDocument.h" #include "nsIRenderingContext.h" #include "nsGUIEvent.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" // Interface IDs //#define DEBUG_REFLOW // static nsIRootBox* nsIRootBox::GetRootBox(nsIPresShell* aShell) { if (!aShell) { return nsnull; } nsIFrame* rootFrame = aShell->FrameManager()->GetRootFrame(); if (!rootFrame) { return nsnull; } if (rootFrame) { rootFrame = rootFrame->GetFirstChild(nsnull); } nsIRootBox* rootBox = nsnull; if (rootFrame) { CallQueryInterface(rootFrame, &rootBox); } return rootBox; } class nsRootBoxFrame : public nsBoxFrame, public nsIRootBox { public: friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext *aContext); NS_DECL_ISUPPORTS_INHERITED virtual nsPopupSetFrame* GetPopupSetFrame(); virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet); virtual nsIContent* GetDefaultTooltip(); virtual void SetDefaultTooltip(nsIContent* aTooltip); virtual nsresult AddTooltipSupport(nsIContent* aNode); virtual nsresult RemoveTooltipSupport(nsIContent* aNode); NS_IMETHOD AppendFrames(nsIAtom* aListName, nsIFrame* aFrameList); NS_IMETHOD InsertFrames(nsIAtom* aListName, nsIFrame* aPrevFrame, nsIFrame* aFrameList); NS_IMETHOD RemoveFrame(nsIAtom* aListName, nsIFrame* aOldFrame); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); NS_IMETHOD HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus); NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); /** * Get the "type" of the frame * * @see nsGkAtoms::rootFrame */ virtual nsIAtom* GetType() const; virtual PRBool IsFrameOfType(PRUint32 aFlags) const { // Override bogus IsFrameOfType in nsBoxFrame. if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced)) return PR_FALSE; return nsBoxFrame::IsFrameOfType(aFlags); } #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif nsPopupSetFrame* mPopupSetFrame; protected: nsIContent* mDefaultTooltip; }; //---------------------------------------------------------------------- nsIFrame* NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { return new (aPresShell) nsRootBoxFrame (aPresShell, aContext); } nsRootBoxFrame::nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext): nsBoxFrame(aShell, aContext, PR_TRUE) { mPopupSetFrame = nsnull; nsCOMPtr layout; NS_NewStackLayout(aShell, layout); SetLayoutManager(layout); } NS_IMETHODIMP nsRootBoxFrame::AppendFrames(nsIAtom* aListName, nsIFrame* aFrameList) { nsresult rv; NS_ASSERTION(!aListName, "unexpected child list name"); NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame"); if (aListName) { // We only support unnamed principal child list rv = NS_ERROR_INVALID_ARG; } else if (!mFrames.IsEmpty()) { // We only allow a single child frame rv = NS_ERROR_FAILURE; } else { rv = nsBoxFrame::AppendFrames(aListName, aFrameList); } return rv; } NS_IMETHODIMP nsRootBoxFrame::InsertFrames(nsIAtom* aListName, nsIFrame* aPrevFrame, nsIFrame* aFrameList) { nsresult rv; // Because we only support a single child frame inserting is the same // as appending NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame"); if (aPrevFrame) { rv = NS_ERROR_UNEXPECTED; } else { rv = AppendFrames(aListName, aFrameList); } return rv; } NS_IMETHODIMP nsRootBoxFrame::RemoveFrame(nsIAtom* aListName, nsIFrame* aOldFrame) { nsresult rv; NS_ASSERTION(!aListName, "unexpected child list name"); if (aListName) { // We only support the unnamed principal child list rv = NS_ERROR_INVALID_ARG; } else if (aOldFrame == mFrames.FirstChild()) { rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame); } else { rv = NS_ERROR_FAILURE; } return rv; } #ifdef DEBUG_REFLOW PRInt32 gReflows = 0; #endif NS_IMETHODIMP nsRootBoxFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame"); #ifdef DEBUG_REFLOW gReflows++; printf("----Reflow %d----\n", gReflows); #endif return nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); } nsresult nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { // 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. nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); return BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); } NS_IMETHODIMP nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } if (aEvent->message == NS_MOUSE_BUTTON_UP) { 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(nsnull)|, 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_IMETHODIMP_(nsrefcnt) nsRootBoxFrame::AddRef(void) { return NS_OK; } NS_IMETHODIMP_(nsrefcnt) nsRootBoxFrame::Release(void) { return NS_OK; } NS_INTERFACE_MAP_BEGIN(nsRootBoxFrame) NS_INTERFACE_MAP_ENTRY(nsIRootBox) NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame) #ifdef DEBUG NS_IMETHODIMP nsRootBoxFrame::GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult); } #endif