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 Communicator client 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 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsFrameList_h___
39 : #define nsFrameList_h___
40 :
41 : #include "nscore.h"
42 : #include "nsTraceRefcnt.h"
43 : #include <stdio.h> /* for FILE* */
44 : #include "nsDebug.h"
45 : #include "nsTArray.h"
46 :
47 : class nsIFrame;
48 : namespace mozilla {
49 : namespace layout {
50 : class FrameChildList;
51 : enum FrameChildListID {
52 : // The individual concrete child lists.
53 : kPrincipalList = 0x1,
54 : kPopupList = 0x2,
55 : kCaptionList = 0x4,
56 : kColGroupList = 0x8,
57 : kSelectPopupList = 0x10,
58 : kAbsoluteList = 0x20,
59 : kFixedList = 0x40,
60 : kOverflowList = 0x80,
61 : kOverflowContainersList = 0x100,
62 : kExcessOverflowContainersList = 0x200,
63 : kOverflowOutOfFlowList = 0x400,
64 : kFloatList = 0x800,
65 : kBulletList = 0x1000,
66 : kPushedFloatsList = 0x2000,
67 : // A special alias for kPrincipalList that suppress the reflow request that
68 : // is normally done when manipulating child lists.
69 : kNoReflowPrincipalList = 0x4000
70 : };
71 : }
72 : }
73 :
74 : // Uncomment this to enable expensive frame-list integrity checking
75 : // #define DEBUG_FRAME_LIST
76 :
77 : /**
78 : * A class for managing a list of frames.
79 : */
80 : class nsFrameList {
81 : public:
82 : nsFrameList() :
83 : mFirstChild(nsnull), mLastChild(nsnull)
84 : {
85 : MOZ_COUNT_CTOR(nsFrameList);
86 : }
87 :
88 : nsFrameList(nsIFrame* aFirstFrame, nsIFrame* aLastFrame) :
89 : mFirstChild(aFirstFrame), mLastChild(aLastFrame)
90 : {
91 : MOZ_COUNT_CTOR(nsFrameList);
92 : VerifyList();
93 : }
94 :
95 0 : nsFrameList(const nsFrameList& aOther) :
96 0 : mFirstChild(aOther.mFirstChild), mLastChild(aOther.mLastChild)
97 : {
98 0 : MOZ_COUNT_CTOR(nsFrameList);
99 0 : }
100 :
101 1403 : ~nsFrameList() {
102 1403 : MOZ_COUNT_DTOR(nsFrameList);
103 : // Don't destroy our frames here, so that we can have temporary nsFrameLists
104 1403 : }
105 :
106 : /**
107 : * For each frame in this list: remove it from the list then call
108 : * Destroy() on it.
109 : */
110 : void DestroyFrames();
111 :
112 : /**
113 : * For each frame in this list: remove it from the list then call
114 : * DestroyFrom() on it.
115 : */
116 : void DestroyFramesFrom(nsIFrame* aDestructRoot);
117 :
118 : /**
119 : * For each frame in this list: remove it from the list then call
120 : * Destroy() on it. Finally <code>delete this</code>.
121 : *
122 : */
123 : void Destroy();
124 :
125 : /**
126 : * For each frame in this list: remove it from the list then call
127 : * DestroyFrom() on it. Finally <code>delete this</code>.
128 : *
129 : */
130 : void DestroyFrom(nsIFrame* aDestructRoot);
131 :
132 : void Clear() { mFirstChild = mLastChild = nsnull; }
133 :
134 : void SetFrames(nsIFrame* aFrameList);
135 :
136 : void SetFrames(nsFrameList& aFrameList) {
137 : NS_PRECONDITION(!mFirstChild, "Losing frames");
138 :
139 : mFirstChild = aFrameList.FirstChild();
140 : mLastChild = aFrameList.LastChild();
141 : aFrameList.Clear();
142 : }
143 :
144 : class Slice;
145 :
146 : /**
147 : * Append aFrameList to this list. If aParent is not null,
148 : * reparents the newly added frames. Clears out aFrameList and
149 : * returns a list slice represening the newly-appended frames.
150 : */
151 : Slice AppendFrames(nsIFrame* aParent, nsFrameList& aFrameList) {
152 : return InsertFrames(aParent, LastChild(), aFrameList);
153 : }
154 :
155 :
156 : /**
157 : * Append aFrame to this list. If aParent is not null,
158 : * reparents the newly added frame.
159 : */
160 : void AppendFrame(nsIFrame* aParent, nsIFrame* aFrame) {
161 : nsFrameList temp(aFrame, aFrame);
162 : AppendFrames(aParent, temp);
163 : }
164 :
165 : /**
166 : * Take aFrame out of the frame list. This also disconnects aFrame
167 : * from the sibling list. The frame must be non-null and present on
168 : * this list.
169 : */
170 : void RemoveFrame(nsIFrame* aFrame);
171 :
172 : /**
173 : * Take aFrame out of the frame list, if present. This also disconnects
174 : * aFrame from the sibling list. aFrame must be non-null but is not
175 : * required to be on the list.
176 : * @return true if aFrame was removed
177 : */
178 : bool RemoveFrameIfPresent(nsIFrame* aFrame);
179 :
180 : /**
181 : * Take the frames after aAfterFrame out of the frame list. If
182 : * aAfterFrame is null, removes the entire list.
183 : * @param aAfterFrame a frame in this list, or null
184 : * @return the removed frames, if any
185 : */
186 : nsFrameList RemoveFramesAfter(nsIFrame* aAfterFrame);
187 :
188 : /**
189 : * Take the first frame (if any) out of the frame list.
190 : * @return the first child, or nsnull if the list is empty
191 : */
192 : nsIFrame* RemoveFirstChild();
193 :
194 : /**
195 : * Take aFrame out of the frame list and then destroy it.
196 : * The frame must be non-null and present on this list.
197 : */
198 : void DestroyFrame(nsIFrame* aFrame);
199 :
200 : /**
201 : * If aFrame is present on this list then take it out of the list and
202 : * then destroy it. The frame must be non-null.
203 : * @return true if the frame was found
204 : */
205 : bool DestroyFrameIfPresent(nsIFrame* aFrame);
206 :
207 : /**
208 : * Insert aFrame right after aPrevSibling, or prepend it to this
209 : * list if aPrevSibling is null. If aParent is not null, also
210 : * reparents newly-added frame. Note that this method always
211 : * sets the frame's nextSibling pointer.
212 : */
213 : void InsertFrame(nsIFrame* aParent, nsIFrame* aPrevSibling,
214 : nsIFrame* aFrame) {
215 : nsFrameList temp(aFrame, aFrame);
216 : InsertFrames(aParent, aPrevSibling, temp);
217 : }
218 :
219 :
220 : /**
221 : * Inserts aFrameList into this list after aPrevSibling (at the beginning if
222 : * aPrevSibling is null). If aParent is not null, reparents the newly added
223 : * frames. Clears out aFrameList and returns a list slice representing the
224 : * newly-inserted frames.
225 : */
226 : Slice InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
227 : nsFrameList& aFrameList);
228 :
229 : class FrameLinkEnumerator;
230 :
231 : /**
232 : * Split this frame list such that all the frames before the link pointed to
233 : * by aLink end up in the returned list, while the remaining frames stay in
234 : * this list. After this call, aLink points to the beginning of this list.
235 : */
236 : nsFrameList ExtractHead(FrameLinkEnumerator& aLink);
237 :
238 : /**
239 : * Split this frame list such that all the frames coming after the link
240 : * pointed to by aLink end up in the returned list, while the frames before
241 : * that link stay in this list. After this call, aLink is at end.
242 : */
243 : nsFrameList ExtractTail(FrameLinkEnumerator& aLink);
244 :
245 0 : nsIFrame* FirstChild() const {
246 0 : return mFirstChild;
247 : }
248 :
249 0 : nsIFrame* LastChild() const {
250 0 : return mLastChild;
251 : }
252 :
253 : nsIFrame* FrameAt(PRInt32 aIndex) const;
254 : PRInt32 IndexOf(nsIFrame* aFrame) const;
255 :
256 : bool IsEmpty() const {
257 : return nsnull == mFirstChild;
258 : }
259 :
260 : bool NotEmpty() const {
261 : return nsnull != mFirstChild;
262 : }
263 :
264 : bool ContainsFrame(const nsIFrame* aFrame) const;
265 :
266 : PRInt32 GetLength() const;
267 :
268 : /**
269 : * If this frame list has only one frame, return that frame.
270 : * Otherwise, return null.
271 : */
272 : nsIFrame* OnlyChild() const {
273 : if (FirstChild() == LastChild()) {
274 : return FirstChild();
275 : }
276 : return nsnull;
277 : }
278 :
279 : /**
280 : * Call SetParent(aParent) for each frame in this list.
281 : * @param aParent the new parent frame, must be non-null
282 : */
283 : void ApplySetParent(nsIFrame* aParent) const;
284 :
285 : /**
286 : * If this frame list is non-empty then append it to aLists as the
287 : * aListID child list.
288 : * (this method is implemented in FrameChildList.h for dependency reasons)
289 : */
290 : inline void AppendIfNonempty(nsTArray<mozilla::layout::FrameChildList>* aLists,
291 : mozilla::layout::FrameChildListID aListID) const;
292 :
293 : #ifdef IBMBIDI
294 : /**
295 : * Return the frame before this frame in visual order (after Bidi reordering).
296 : * If aFrame is null, return the last frame in visual order.
297 : */
298 : nsIFrame* GetPrevVisualFor(nsIFrame* aFrame) const;
299 :
300 : /**
301 : * Return the frame after this frame in visual order (after Bidi reordering).
302 : * If aFrame is null, return the first frame in visual order.
303 : */
304 : nsIFrame* GetNextVisualFor(nsIFrame* aFrame) const;
305 : #endif // IBMBIDI
306 :
307 : #ifdef DEBUG
308 : void List(FILE* out) const;
309 : #endif
310 :
311 : static void Init();
312 2806 : static void Shutdown() { delete sEmptyList; }
313 : static const nsFrameList& EmptyList() { return *sEmptyList; }
314 :
315 : class Enumerator;
316 :
317 : /**
318 : * A class representing a slice of a frame list.
319 : */
320 : class Slice {
321 : friend class Enumerator;
322 :
323 : public:
324 : // Implicit on purpose, so that we can easily create enumerators from
325 : // nsFrameList via this impicit constructor.
326 0 : Slice(const nsFrameList& aList) :
327 : #ifdef DEBUG
328 : mList(aList),
329 : #endif
330 0 : mStart(aList.FirstChild()),
331 0 : mEnd(nsnull)
332 0 : {}
333 :
334 : Slice(const nsFrameList& aList, nsIFrame* aStart, nsIFrame* aEnd) :
335 : #ifdef DEBUG
336 : mList(aList),
337 : #endif
338 : mStart(aStart),
339 : mEnd(aEnd)
340 : {}
341 :
342 0 : Slice(const Slice& aOther) :
343 : #ifdef DEBUG
344 : mList(aOther.mList),
345 : #endif
346 : mStart(aOther.mStart),
347 0 : mEnd(aOther.mEnd)
348 0 : {}
349 :
350 : private:
351 : #ifdef DEBUG
352 : const nsFrameList& mList;
353 : #endif
354 : nsIFrame* const mStart; // our starting frame
355 : const nsIFrame* const mEnd; // The first frame that is NOT in the slice.
356 : // May be null.
357 : };
358 :
359 : class Enumerator {
360 : public:
361 0 : Enumerator(const Slice& aSlice) :
362 : #ifdef DEBUG
363 : mSlice(aSlice),
364 : #endif
365 : mFrame(aSlice.mStart),
366 0 : mEnd(aSlice.mEnd)
367 0 : {}
368 :
369 : Enumerator(const Enumerator& aOther) :
370 : #ifdef DEBUG
371 : mSlice(aOther.mSlice),
372 : #endif
373 : mFrame(aOther.mFrame),
374 : mEnd(aOther.mEnd)
375 : {}
376 :
377 0 : bool AtEnd() const {
378 : // Can't just check mEnd, because some table code goes and destroys the
379 : // tail of the frame list (including mEnd!) while iterating over the
380 : // frame list.
381 0 : return !mFrame || mFrame == mEnd;
382 : }
383 :
384 : /* Next() needs to know about nsIFrame, and nsIFrame will need to
385 : know about nsFrameList methods, so in order to inline this put
386 : the implementation in nsIFrame.h */
387 : inline void Next();
388 :
389 : /**
390 : * Get the current frame we're pointing to. Do not call this on an
391 : * iterator that is at end!
392 : */
393 0 : nsIFrame* get() const {
394 0 : NS_PRECONDITION(!AtEnd(), "Enumerator is at end");
395 0 : return mFrame;
396 : }
397 :
398 : /**
399 : * Get an enumerator that is just like this one, but not limited in terms of
400 : * the part of the list it will traverse.
401 : */
402 : Enumerator GetUnlimitedEnumerator() const {
403 : return Enumerator(*this, nsnull);
404 : }
405 :
406 : #ifdef DEBUG
407 : const nsFrameList& List() const { return mSlice.mList; }
408 : #endif
409 :
410 : protected:
411 : Enumerator(const Enumerator& aOther, const nsIFrame* const aNewEnd):
412 : #ifdef DEBUG
413 : mSlice(aOther.mSlice),
414 : #endif
415 : mFrame(aOther.mFrame),
416 : mEnd(aNewEnd)
417 : {}
418 :
419 : #ifdef DEBUG
420 : /* Has to be an object, not a reference, since the slice could
421 : well be a temporary constructed from an nsFrameList */
422 : const Slice mSlice;
423 : #endif
424 : nsIFrame* mFrame; // our current frame.
425 : const nsIFrame* const mEnd; // The first frame we should NOT enumerate.
426 : // May be null.
427 : };
428 :
429 : /**
430 : * A class that can be used to enumerate links between frames. When created
431 : * from an nsFrameList, it points to the "link" immediately before the first
432 : * frame. It can then be advanced until it points to the "link" immediately
433 : * after the last frame. At any position, PrevFrame() and NextFrame() are
434 : * the frames before and after the given link. This means PrevFrame() is
435 : * null when the enumerator is at the beginning of the list and NextFrame()
436 : * is null when it's AtEnd().
437 : */
438 : class FrameLinkEnumerator : private Enumerator {
439 : public:
440 : friend class nsFrameList;
441 :
442 : FrameLinkEnumerator(const nsFrameList& aList) :
443 : Enumerator(aList),
444 : mPrev(nsnull)
445 : {}
446 :
447 : FrameLinkEnumerator(const FrameLinkEnumerator& aOther) :
448 : Enumerator(aOther),
449 : mPrev(aOther.mPrev)
450 : {}
451 :
452 : /* This constructor needs to know about nsIFrame, and nsIFrame will need to
453 : know about nsFrameList methods, so in order to inline this put
454 : the implementation in nsIFrame.h */
455 : inline FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame);
456 :
457 : void operator=(const FrameLinkEnumerator& aOther) {
458 : NS_PRECONDITION(&List() == &aOther.List(), "Different lists?");
459 : mFrame = aOther.mFrame;
460 : mPrev = aOther.mPrev;
461 : }
462 :
463 : void Next() {
464 : mPrev = mFrame;
465 : Enumerator::Next();
466 : }
467 :
468 : bool AtEnd() const { return Enumerator::AtEnd(); }
469 :
470 : nsIFrame* PrevFrame() const { return mPrev; }
471 : nsIFrame* NextFrame() const { return mFrame; }
472 :
473 : protected:
474 : nsIFrame* mPrev;
475 : };
476 :
477 : private:
478 : #ifdef DEBUG_FRAME_LIST
479 : void VerifyList() const;
480 : #else
481 : void VerifyList() const {}
482 : #endif
483 :
484 : static const nsFrameList* sEmptyList;
485 :
486 : protected:
487 : nsIFrame* mFirstChild;
488 : nsIFrame* mLastChild;
489 : };
490 :
491 : #endif /* nsFrameList_h___ */
|