Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "nsHTMLParts.h" |
michael@0 | 7 | #include "nsStyleConsts.h" |
michael@0 | 8 | #include "nsGkAtoms.h" |
michael@0 | 9 | #include "nsIPresShell.h" |
michael@0 | 10 | #include "nsBoxFrame.h" |
michael@0 | 11 | #include "nsStackLayout.h" |
michael@0 | 12 | #include "nsIRootBox.h" |
michael@0 | 13 | #include "nsIContent.h" |
michael@0 | 14 | #include "nsXULTooltipListener.h" |
michael@0 | 15 | #include "nsFrameManager.h" |
michael@0 | 16 | #include "mozilla/BasicEvents.h" |
michael@0 | 17 | |
michael@0 | 18 | using namespace mozilla; |
michael@0 | 19 | |
michael@0 | 20 | // Interface IDs |
michael@0 | 21 | |
michael@0 | 22 | //#define DEBUG_REFLOW |
michael@0 | 23 | |
michael@0 | 24 | // static |
michael@0 | 25 | nsIRootBox* |
michael@0 | 26 | nsIRootBox::GetRootBox(nsIPresShell* aShell) |
michael@0 | 27 | { |
michael@0 | 28 | if (!aShell) { |
michael@0 | 29 | return nullptr; |
michael@0 | 30 | } |
michael@0 | 31 | nsIFrame* rootFrame = aShell->FrameManager()->GetRootFrame(); |
michael@0 | 32 | if (!rootFrame) { |
michael@0 | 33 | return nullptr; |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | if (rootFrame) { |
michael@0 | 37 | rootFrame = rootFrame->GetFirstPrincipalChild(); |
michael@0 | 38 | } |
michael@0 | 39 | |
michael@0 | 40 | nsIRootBox* rootBox = do_QueryFrame(rootFrame); |
michael@0 | 41 | return rootBox; |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | class nsRootBoxFrame : public nsBoxFrame, public nsIRootBox { |
michael@0 | 45 | public: |
michael@0 | 46 | |
michael@0 | 47 | friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); |
michael@0 | 48 | |
michael@0 | 49 | nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext *aContext); |
michael@0 | 50 | |
michael@0 | 51 | NS_DECL_QUERYFRAME |
michael@0 | 52 | NS_DECL_FRAMEARENA_HELPERS |
michael@0 | 53 | |
michael@0 | 54 | virtual nsPopupSetFrame* GetPopupSetFrame() MOZ_OVERRIDE; |
michael@0 | 55 | virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) MOZ_OVERRIDE; |
michael@0 | 56 | virtual nsIContent* GetDefaultTooltip() MOZ_OVERRIDE; |
michael@0 | 57 | virtual void SetDefaultTooltip(nsIContent* aTooltip) MOZ_OVERRIDE; |
michael@0 | 58 | virtual nsresult AddTooltipSupport(nsIContent* aNode) MOZ_OVERRIDE; |
michael@0 | 59 | virtual nsresult RemoveTooltipSupport(nsIContent* aNode) MOZ_OVERRIDE; |
michael@0 | 60 | |
michael@0 | 61 | virtual nsresult AppendFrames(ChildListID aListID, |
michael@0 | 62 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 63 | virtual nsresult InsertFrames(ChildListID aListID, |
michael@0 | 64 | nsIFrame* aPrevFrame, |
michael@0 | 65 | nsFrameList& aFrameList) MOZ_OVERRIDE; |
michael@0 | 66 | virtual nsresult RemoveFrame(ChildListID aListID, |
michael@0 | 67 | nsIFrame* aOldFrame) MOZ_OVERRIDE; |
michael@0 | 68 | |
michael@0 | 69 | virtual nsresult Reflow(nsPresContext* aPresContext, |
michael@0 | 70 | nsHTMLReflowMetrics& aDesiredSize, |
michael@0 | 71 | const nsHTMLReflowState& aReflowState, |
michael@0 | 72 | nsReflowStatus& aStatus) MOZ_OVERRIDE; |
michael@0 | 73 | virtual nsresult HandleEvent(nsPresContext* aPresContext, |
michael@0 | 74 | WidgetGUIEvent* aEvent, |
michael@0 | 75 | nsEventStatus* aEventStatus) MOZ_OVERRIDE; |
michael@0 | 76 | |
michael@0 | 77 | virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
michael@0 | 78 | const nsRect& aDirtyRect, |
michael@0 | 79 | const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
michael@0 | 80 | |
michael@0 | 81 | /** |
michael@0 | 82 | * Get the "type" of the frame |
michael@0 | 83 | * |
michael@0 | 84 | * @see nsGkAtoms::rootFrame |
michael@0 | 85 | */ |
michael@0 | 86 | virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
michael@0 | 87 | |
michael@0 | 88 | virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
michael@0 | 89 | { |
michael@0 | 90 | // Override bogus IsFrameOfType in nsBoxFrame. |
michael@0 | 91 | if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced)) |
michael@0 | 92 | return false; |
michael@0 | 93 | return nsBoxFrame::IsFrameOfType(aFlags); |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | #ifdef DEBUG_FRAME_DUMP |
michael@0 | 97 | virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; |
michael@0 | 98 | #endif |
michael@0 | 99 | |
michael@0 | 100 | nsPopupSetFrame* mPopupSetFrame; |
michael@0 | 101 | |
michael@0 | 102 | protected: |
michael@0 | 103 | nsIContent* mDefaultTooltip; |
michael@0 | 104 | }; |
michael@0 | 105 | |
michael@0 | 106 | //---------------------------------------------------------------------- |
michael@0 | 107 | |
michael@0 | 108 | nsIFrame* |
michael@0 | 109 | NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
michael@0 | 110 | { |
michael@0 | 111 | return new (aPresShell) nsRootBoxFrame (aPresShell, aContext); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | NS_IMPL_FRAMEARENA_HELPERS(nsRootBoxFrame) |
michael@0 | 115 | |
michael@0 | 116 | nsRootBoxFrame::nsRootBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext): |
michael@0 | 117 | nsBoxFrame(aShell, aContext, true) |
michael@0 | 118 | { |
michael@0 | 119 | mPopupSetFrame = nullptr; |
michael@0 | 120 | |
michael@0 | 121 | nsCOMPtr<nsBoxLayout> layout; |
michael@0 | 122 | NS_NewStackLayout(aShell, layout); |
michael@0 | 123 | SetLayoutManager(layout); |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | nsresult |
michael@0 | 127 | nsRootBoxFrame::AppendFrames(ChildListID aListID, |
michael@0 | 128 | nsFrameList& aFrameList) |
michael@0 | 129 | { |
michael@0 | 130 | nsresult rv; |
michael@0 | 131 | |
michael@0 | 132 | NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID"); |
michael@0 | 133 | NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame"); |
michael@0 | 134 | if (aListID != kPrincipalList) { |
michael@0 | 135 | // We only support the principal child list. |
michael@0 | 136 | rv = NS_ERROR_INVALID_ARG; |
michael@0 | 137 | } else if (!mFrames.IsEmpty()) { |
michael@0 | 138 | // We only allow a single child frame. |
michael@0 | 139 | rv = NS_ERROR_FAILURE; |
michael@0 | 140 | } else { |
michael@0 | 141 | rv = nsBoxFrame::AppendFrames(aListID, aFrameList); |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | return rv; |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | nsresult |
michael@0 | 148 | nsRootBoxFrame::InsertFrames(ChildListID aListID, |
michael@0 | 149 | nsIFrame* aPrevFrame, |
michael@0 | 150 | nsFrameList& aFrameList) |
michael@0 | 151 | { |
michael@0 | 152 | nsresult rv; |
michael@0 | 153 | |
michael@0 | 154 | // Because we only support a single child frame inserting is the same |
michael@0 | 155 | // as appending. |
michael@0 | 156 | NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame"); |
michael@0 | 157 | if (aPrevFrame) { |
michael@0 | 158 | rv = NS_ERROR_UNEXPECTED; |
michael@0 | 159 | } else { |
michael@0 | 160 | rv = AppendFrames(aListID, aFrameList); |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | return rv; |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | nsresult |
michael@0 | 167 | nsRootBoxFrame::RemoveFrame(ChildListID aListID, |
michael@0 | 168 | nsIFrame* aOldFrame) |
michael@0 | 169 | { |
michael@0 | 170 | nsresult rv; |
michael@0 | 171 | |
michael@0 | 172 | NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID"); |
michael@0 | 173 | if (aListID != kPrincipalList) { |
michael@0 | 174 | // We only support the principal child list. |
michael@0 | 175 | rv = NS_ERROR_INVALID_ARG; |
michael@0 | 176 | } else if (aOldFrame == mFrames.FirstChild()) { |
michael@0 | 177 | rv = nsBoxFrame::RemoveFrame(aListID, aOldFrame); |
michael@0 | 178 | } else { |
michael@0 | 179 | rv = NS_ERROR_FAILURE; |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | return rv; |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | #ifdef DEBUG_REFLOW |
michael@0 | 186 | int32_t gReflows = 0; |
michael@0 | 187 | #endif |
michael@0 | 188 | |
michael@0 | 189 | nsresult |
michael@0 | 190 | nsRootBoxFrame::Reflow(nsPresContext* aPresContext, |
michael@0 | 191 | nsHTMLReflowMetrics& aDesiredSize, |
michael@0 | 192 | const nsHTMLReflowState& aReflowState, |
michael@0 | 193 | nsReflowStatus& aStatus) |
michael@0 | 194 | { |
michael@0 | 195 | DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame"); |
michael@0 | 196 | |
michael@0 | 197 | #ifdef DEBUG_REFLOW |
michael@0 | 198 | gReflows++; |
michael@0 | 199 | printf("----Reflow %d----\n", gReflows); |
michael@0 | 200 | #endif |
michael@0 | 201 | return nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | void |
michael@0 | 205 | nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
michael@0 | 206 | const nsRect& aDirtyRect, |
michael@0 | 207 | const nsDisplayListSet& aLists) |
michael@0 | 208 | { |
michael@0 | 209 | // root boxes don't need a debug border/outline or a selection overlay... |
michael@0 | 210 | // They *may* have a background propagated to them, so force creation |
michael@0 | 211 | // of a background display list element. |
michael@0 | 212 | DisplayBorderBackgroundOutline(aBuilder, aLists, true); |
michael@0 | 213 | |
michael@0 | 214 | BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | nsresult |
michael@0 | 218 | nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext, |
michael@0 | 219 | WidgetGUIEvent* aEvent, |
michael@0 | 220 | nsEventStatus* aEventStatus) |
michael@0 | 221 | { |
michael@0 | 222 | NS_ENSURE_ARG_POINTER(aEventStatus); |
michael@0 | 223 | if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { |
michael@0 | 224 | return NS_OK; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | if (aEvent->message == NS_MOUSE_BUTTON_UP) { |
michael@0 | 228 | nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | return NS_OK; |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | // REVIEW: The override here was doing nothing since nsBoxFrame is our |
michael@0 | 235 | // parent class |
michael@0 | 236 | nsIAtom* |
michael@0 | 237 | nsRootBoxFrame::GetType() const |
michael@0 | 238 | { |
michael@0 | 239 | return nsGkAtoms::rootFrame; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | nsPopupSetFrame* |
michael@0 | 243 | nsRootBoxFrame::GetPopupSetFrame() |
michael@0 | 244 | { |
michael@0 | 245 | return mPopupSetFrame; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | void |
michael@0 | 249 | nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet) |
michael@0 | 250 | { |
michael@0 | 251 | // Under normal conditions this should only be called once. However, |
michael@0 | 252 | // if something triggers ReconstructDocElementHierarchy, we will |
michael@0 | 253 | // destroy this frame's child (the nsDocElementBoxFrame), but not this |
michael@0 | 254 | // frame. This will cause the popupset to remove itself by calling |
michael@0 | 255 | // |SetPopupSetFrame(nullptr)|, and then we'll be able to accept a new |
michael@0 | 256 | // popupset. Since the anonymous content is associated with the |
michael@0 | 257 | // nsDocElementBoxFrame, we'll get a new popupset when the new doc |
michael@0 | 258 | // element box frame is created. |
michael@0 | 259 | if (!mPopupSetFrame || !aPopupSet) { |
michael@0 | 260 | mPopupSetFrame = aPopupSet; |
michael@0 | 261 | } else { |
michael@0 | 262 | NS_NOTREACHED("Popup set is already defined! Only 1 allowed."); |
michael@0 | 263 | } |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | nsIContent* |
michael@0 | 267 | nsRootBoxFrame::GetDefaultTooltip() |
michael@0 | 268 | { |
michael@0 | 269 | return mDefaultTooltip; |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | void |
michael@0 | 273 | nsRootBoxFrame::SetDefaultTooltip(nsIContent* aTooltip) |
michael@0 | 274 | { |
michael@0 | 275 | mDefaultTooltip = aTooltip; |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | nsresult |
michael@0 | 279 | nsRootBoxFrame::AddTooltipSupport(nsIContent* aNode) |
michael@0 | 280 | { |
michael@0 | 281 | NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); |
michael@0 | 282 | |
michael@0 | 283 | nsXULTooltipListener *listener = nsXULTooltipListener::GetInstance(); |
michael@0 | 284 | if (!listener) |
michael@0 | 285 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 286 | |
michael@0 | 287 | return listener->AddTooltipSupport(aNode); |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | nsresult |
michael@0 | 291 | nsRootBoxFrame::RemoveTooltipSupport(nsIContent* aNode) |
michael@0 | 292 | { |
michael@0 | 293 | // XXjh yuck, I'll have to implement a way to get at |
michael@0 | 294 | // the tooltip listener for a given node to make |
michael@0 | 295 | // this work. Not crucial, we aren't removing |
michael@0 | 296 | // tooltips from any nodes in the app just yet. |
michael@0 | 297 | return NS_ERROR_NOT_IMPLEMENTED; |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | NS_QUERYFRAME_HEAD(nsRootBoxFrame) |
michael@0 | 301 | NS_QUERYFRAME_ENTRY(nsIRootBox) |
michael@0 | 302 | NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) |
michael@0 | 303 | |
michael@0 | 304 | #ifdef DEBUG_FRAME_DUMP |
michael@0 | 305 | nsresult |
michael@0 | 306 | nsRootBoxFrame::GetFrameName(nsAString& aResult) const |
michael@0 | 307 | { |
michael@0 | 308 | return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult); |
michael@0 | 309 | } |
michael@0 | 310 | #endif |