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