1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Original Author: David W. Hyatt (hyatt@netscape.com)
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : * Dean Tessman <dean_tessman@hotmail.com>
26 : * Mats Palmgren <matspal@gmail.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsPopupSetFrame.h"
43 : #include "nsGkAtoms.h"
44 : #include "nsCOMPtr.h"
45 : #include "nsIContent.h"
46 : #include "nsPresContext.h"
47 : #include "nsStyleContext.h"
48 : #include "nsBoxLayoutState.h"
49 : #include "nsIScrollableFrame.h"
50 : #include "nsIRootBox.h"
51 : #include "nsMenuPopupFrame.h"
52 :
53 : nsIFrame*
54 0 : NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
55 : {
56 0 : return new (aPresShell) nsPopupSetFrame (aPresShell, aContext);
57 : }
58 :
59 0 : NS_IMPL_FRAMEARENA_HELPERS(nsPopupSetFrame)
60 :
61 : NS_IMETHODIMP
62 0 : nsPopupSetFrame::Init(nsIContent* aContent,
63 : nsIFrame* aParent,
64 : nsIFrame* aPrevInFlow)
65 : {
66 0 : nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
67 :
68 : // Normally the root box is our grandparent, but in case of wrapping
69 : // it can be our great-grandparent.
70 0 : nsIRootBox *rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell());
71 0 : if (rootBox) {
72 0 : rootBox->SetPopupSetFrame(this);
73 : }
74 :
75 0 : return rv;
76 : }
77 :
78 : nsIAtom*
79 0 : nsPopupSetFrame::GetType() const
80 : {
81 0 : return nsGkAtoms::popupSetFrame;
82 : }
83 :
84 : NS_IMETHODIMP
85 0 : nsPopupSetFrame::AppendFrames(ChildListID aListID,
86 : nsFrameList& aFrameList)
87 : {
88 0 : if (aListID == kPopupList) {
89 0 : AddPopupFrameList(aFrameList);
90 0 : return NS_OK;
91 : }
92 0 : return nsBoxFrame::AppendFrames(aListID, aFrameList);
93 : }
94 :
95 : NS_IMETHODIMP
96 0 : nsPopupSetFrame::RemoveFrame(ChildListID aListID,
97 : nsIFrame* aOldFrame)
98 : {
99 0 : if (aListID == kPopupList) {
100 0 : RemovePopupFrame(aOldFrame);
101 0 : return NS_OK;
102 : }
103 0 : return nsBoxFrame::RemoveFrame(aListID, aOldFrame);
104 : }
105 :
106 : NS_IMETHODIMP
107 0 : nsPopupSetFrame::InsertFrames(ChildListID aListID,
108 : nsIFrame* aPrevFrame,
109 : nsFrameList& aFrameList)
110 : {
111 0 : if (aListID == kPopupList) {
112 0 : AddPopupFrameList(aFrameList);
113 0 : return NS_OK;
114 : }
115 0 : return nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
116 : }
117 :
118 : NS_IMETHODIMP
119 0 : nsPopupSetFrame::SetInitialChildList(ChildListID aListID,
120 : nsFrameList& aChildList)
121 : {
122 0 : if (aListID == kPopupList) {
123 : // XXXmats this asserts because we don't implement
124 : // GetChildList(kPopupList) so nsCSSFrameConstructor
125 : // believes it's empty and calls us multiple times.
126 : //NS_ASSERTION(mPopupList.IsEmpty(),
127 : // "SetInitialChildList on non-empty child list");
128 0 : AddPopupFrameList(aChildList);
129 0 : return NS_OK;
130 : }
131 0 : return nsBoxFrame::SetInitialChildList(aListID, aChildList);
132 : }
133 :
134 : void
135 0 : nsPopupSetFrame::DestroyFrom(nsIFrame* aDestructRoot)
136 : {
137 0 : mPopupList.DestroyFramesFrom(aDestructRoot);
138 :
139 : // Normally the root box is our grandparent, but in case of wrapping
140 : // it can be our great-grandparent.
141 0 : nsIRootBox *rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell());
142 0 : if (rootBox) {
143 0 : rootBox->SetPopupSetFrame(nsnull);
144 : }
145 :
146 0 : nsBoxFrame::DestroyFrom(aDestructRoot);
147 0 : }
148 :
149 : NS_IMETHODIMP
150 0 : nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
151 : {
152 : // lay us out
153 0 : nsresult rv = nsBoxFrame::DoLayout(aState);
154 :
155 : // lay out all of our currently open popups.
156 0 : for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) {
157 0 : nsMenuPopupFrame* popupChild = static_cast<nsMenuPopupFrame*>(e.get());
158 0 : popupChild->LayoutPopup(aState, nsnull, false);
159 : }
160 :
161 0 : return rv;
162 : }
163 :
164 : void
165 0 : nsPopupSetFrame::RemovePopupFrame(nsIFrame* aPopup)
166 : {
167 0 : NS_PRECONDITION((aPopup->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
168 : aPopup->GetType() == nsGkAtoms::menuPopupFrame,
169 : "removing wrong type of frame in popupset's ::popupList");
170 :
171 0 : mPopupList.DestroyFrame(aPopup);
172 0 : }
173 :
174 : void
175 0 : nsPopupSetFrame::AddPopupFrameList(nsFrameList& aPopupFrameList)
176 : {
177 : #ifdef DEBUG
178 0 : for (nsFrameList::Enumerator e(aPopupFrameList); !e.AtEnd(); e.Next()) {
179 0 : NS_ASSERTION((e.get()->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
180 : e.get()->GetType() == nsGkAtoms::menuPopupFrame,
181 : "adding wrong type of frame in popupset's ::popupList");
182 : }
183 : #endif
184 0 : mPopupList.InsertFrames(nsnull, nsnull, aPopupFrameList);
185 0 : }
186 :
187 : #ifdef DEBUG
188 : NS_IMETHODIMP
189 0 : nsPopupSetFrame::List(FILE* out, PRInt32 aIndent) const
190 : {
191 0 : IndentBy(out, aIndent);
192 0 : ListTag(out);
193 : #ifdef DEBUG_waterson
194 : fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
195 : #endif
196 0 : if (HasView()) {
197 0 : fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
198 : }
199 0 : if (GetNextSibling()) {
200 0 : fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
201 : }
202 0 : if (nsnull != GetPrevContinuation()) {
203 0 : fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
204 : }
205 0 : if (nsnull != GetNextContinuation()) {
206 0 : fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
207 : }
208 0 : fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
209 0 : if (0 != mState) {
210 0 : fprintf(out, " [state=%016llx]", (unsigned long long)mState);
211 : }
212 0 : fprintf(out, " [content=%p]", static_cast<void*>(mContent));
213 0 : nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
214 0 : if (f->HasOverflowAreas()) {
215 0 : nsRect overflowArea = f->GetVisualOverflowRect();
216 : fprintf(out, " [vis-overflow=%d,%d,%d,%d]",
217 : overflowArea.x, overflowArea.y,
218 0 : overflowArea.width, overflowArea.height);
219 0 : overflowArea = f->GetScrollableOverflowRect();
220 : fprintf(out, " [scr-overflow=%d,%d,%d,%d]",
221 : overflowArea.x, overflowArea.y,
222 0 : overflowArea.width, overflowArea.height);
223 : }
224 0 : fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
225 0 : nsIAtom* pseudoTag = mStyleContext->GetPseudo();
226 0 : if (pseudoTag) {
227 0 : nsAutoString atomString;
228 0 : pseudoTag->ToString(atomString);
229 : fprintf(out, " pst=%s",
230 0 : NS_LossyConvertUTF16toASCII(atomString).get());
231 : }
232 :
233 : // Output the children
234 0 : bool outputOneList = false;
235 0 : ChildListIterator lists(this);
236 0 : for (; !lists.IsDone(); lists.Next()) {
237 0 : if (outputOneList) {
238 0 : IndentBy(out, aIndent);
239 : }
240 0 : outputOneList = true;
241 0 : fprintf(out, "%s<\n", mozilla::layout::ChildListName(lists.CurrentID()));
242 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
243 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
244 0 : nsIFrame* kid = childFrames.get();
245 : // Verify the child frame's parent frame pointer is correct
246 0 : NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
247 :
248 : // Have the child frame list
249 0 : kid->List(out, aIndent + 1);
250 : }
251 0 : IndentBy(out, aIndent);
252 0 : fputs(">\n", out);
253 : }
254 :
255 : // XXXmats the above is copy-pasted from nsContainerFrame::List which is lame,
256 : // clean this up after bug 399111 is implemented.
257 :
258 0 : if (!mPopupList.IsEmpty()) {
259 0 : fputs("<\n", out);
260 0 : ++aIndent;
261 0 : IndentBy(out, aIndent);
262 0 : fputs(mozilla::layout::ChildListName(kPopupList), out);
263 0 : fputs(" for ", out);
264 0 : ListTag(out);
265 0 : fputs(" <\n", out);
266 0 : ++aIndent;
267 0 : for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) {
268 0 : e.get()->List(out, aIndent);
269 : }
270 0 : --aIndent;
271 0 : IndentBy(out, aIndent);
272 0 : fputs(">\n", out);
273 0 : --aIndent;
274 0 : IndentBy(out, aIndent);
275 0 : fputs(">\n", out);
276 0 : outputOneList = true;
277 : }
278 :
279 0 : if (!outputOneList) {
280 0 : fputs("<>\n", out);
281 : }
282 :
283 0 : return NS_OK;
284 : }
285 : #endif
|