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