layout/generic/nsContainerFrame.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:e93b57e9e97b
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 /* base class #1 for rendering objects that have child lists */
7
8 #ifndef nsContainerFrame_h___
9 #define nsContainerFrame_h___
10
11 #include "mozilla/Attributes.h"
12 #include "nsSplittableFrame.h"
13 #include "nsFrameList.h"
14 #include "nsLayoutUtils.h"
15
16 // Option flags for ReflowChild() and FinishReflowChild()
17 // member functions
18 #define NS_FRAME_NO_MOVE_VIEW 0x0001
19 #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
20 #define NS_FRAME_NO_SIZE_VIEW 0x0004
21 #define NS_FRAME_NO_VISIBILITY 0x0008
22 // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
23 // if the reflow is fully complete.
24 #define NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD 0x0010
25
26 class nsOverflowContinuationTracker;
27 namespace mozilla {
28 class FramePropertyTable;
29 }
30
31 // Some macros for container classes to do sanity checking on
32 // width/height/x/y values computed during reflow.
33 // NOTE: AppUnitsPerCSSPixel value hardwired here to remove the
34 // dependency on nsDeviceContext.h. It doesn't matter if it's a
35 // little off.
36 #ifdef DEBUG
37 #define CRAZY_COORD (1000000*60)
38 #define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
39 #endif
40
41 /**
42 * Implementation of a container frame.
43 */
44 class nsContainerFrame : public nsSplittableFrame
45 {
46 public:
47 NS_DECL_FRAMEARENA_HELPERS
48 NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
49 NS_DECL_QUERYFRAME
50
51 // nsIFrame overrides
52 virtual void Init(nsIContent* aContent,
53 nsIFrame* aParent,
54 nsIFrame* aPrevInFlow) MOZ_OVERRIDE;
55 virtual nsresult SetInitialChildList(ChildListID aListID,
56 nsFrameList& aChildList) MOZ_OVERRIDE;
57 virtual nsresult AppendFrames(ChildListID aListID,
58 nsFrameList& aFrameList) MOZ_OVERRIDE;
59 virtual nsresult InsertFrames(ChildListID aListID,
60 nsIFrame* aPrevFrame,
61 nsFrameList& aFrameList) MOZ_OVERRIDE;
62 virtual nsresult RemoveFrame(ChildListID aListID,
63 nsIFrame* aOldFrame) MOZ_OVERRIDE;
64
65 virtual const nsFrameList& GetChildList(ChildListID aList) const MOZ_OVERRIDE;
66 virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
67 virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
68 virtual void ChildIsDirty(nsIFrame* aChild) MOZ_OVERRIDE;
69
70 virtual bool IsLeaf() const MOZ_OVERRIDE;
71 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE;
72 virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
73 bool aRespectClusters = true) MOZ_OVERRIDE;
74
75 #ifdef DEBUG_FRAME_DUMP
76 void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
77 #endif
78
79 // nsContainerFrame methods
80
81 /**
82 * Helper method to create next-in-flows if necessary. If aFrame
83 * already has a next-in-flow then this method does
84 * nothing. Otherwise, a new continuation frame is created and
85 * linked into the flow. In addition, the new frame is inserted
86 * into the principal child list after aFrame.
87 * @note calling this method on a block frame is illegal. Use
88 * nsBlockFrame::CreateContinuationFor() instead.
89 * @param aNextInFlowResult will contain the next-in-flow
90 * <b>if and only if</b> one is created. If a next-in-flow already
91 * exists aNextInFlowResult is set to nullptr.
92 * @return NS_OK if a next-in-flow already exists or is successfully created.
93 */
94 nsresult CreateNextInFlow(nsIFrame* aFrame, nsIFrame*& aNextInFlowResult);
95
96 /**
97 * Delete aNextInFlow and its next-in-flows.
98 * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
99 * content was complete before aNextInFlow, so aNextInFlow and its
100 * next-in-flows no longer map any real content.
101 */
102 virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow,
103 bool aDeletingEmptyFrames);
104
105 /**
106 * Helper method to wrap views around frames. Used by containers
107 * under special circumstances (can be used by leaf frames as well)
108 */
109 static void CreateViewForFrame(nsIFrame* aFrame,
110 bool aForce);
111
112 // Positions the frame's view based on the frame's origin
113 static void PositionFrameView(nsIFrame* aKidFrame);
114
115 static nsresult ReparentFrameView(nsIFrame* aChildFrame,
116 nsIFrame* aOldParentFrame,
117 nsIFrame* aNewParentFrame);
118
119 static nsresult ReparentFrameViewList(const nsFrameList& aChildFrameList,
120 nsIFrame* aOldParentFrame,
121 nsIFrame* aNewParentFrame);
122
123 // Set the view's size and position after its frame has been reflowed.
124 //
125 // Flags:
126 // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
127 // don't want to automatically sync the frame and view
128 // NS_FRAME_NO_SIZE_VIEW - don't size the view
129 static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
130 nsIFrame* aFrame,
131 nsView* aView,
132 const nsRect& aVisualOverflowArea,
133 uint32_t aFlags = 0);
134
135 // Syncs properties to the top level view and window, like transparency and
136 // shadow.
137 static void SyncWindowProperties(nsPresContext* aPresContext,
138 nsIFrame* aFrame,
139 nsView* aView,
140 nsRenderingContext* aRC = nullptr);
141
142 // Sets the view's attributes from the frame style.
143 // - visibility
144 // - clip
145 // Call this when one of these styles changes or when the view has just
146 // been created.
147 // @param aStyleContext can be null, in which case the frame's style context is used
148 static void SyncFrameViewProperties(nsPresContext* aPresContext,
149 nsIFrame* aFrame,
150 nsStyleContext* aStyleContext,
151 nsView* aView,
152 uint32_t aFlags = 0);
153
154 /**
155 * Converts the minimum and maximum sizes given in inner window app units to
156 * outer window device pixel sizes and assigns these constraints to the widget.
157 *
158 * @param aPresContext pres context
159 * @param aWidget widget for this frame
160 * @param minimum size of the window in app units
161 * @param maxmimum size of the window in app units
162 */
163 static void SetSizeConstraints(nsPresContext* aPresContext,
164 nsIWidget* aWidget,
165 const nsSize& aMinSize,
166 const nsSize& aMaxSize);
167
168 // Used by both nsInlineFrame and nsFirstLetterFrame.
169 void DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
170 InlineIntrinsicWidthData *aData,
171 nsLayoutUtils::IntrinsicWidthType aType);
172
173 /**
174 * This is the CSS block concept of computing 'auto' widths, which most
175 * classes derived from nsContainerFrame want.
176 */
177 virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
178 nsSize aCBSize, nscoord aAvailableWidth,
179 nsSize aMargin, nsSize aBorder,
180 nsSize aPadding, bool aShrinkWrap) MOZ_OVERRIDE;
181
182 /**
183 * Invokes the WillReflow() function, positions the frame and its view (if
184 * requested), and then calls Reflow(). If the reflow succeeds and the child
185 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
186 *
187 * Flags:
188 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
189 * don't want to automatically sync the frame and view
190 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
191 * case. Also implies NS_FRAME_NO_MOVE_VIEW
192 */
193 nsresult ReflowChild(nsIFrame* aKidFrame,
194 nsPresContext* aPresContext,
195 nsHTMLReflowMetrics& aDesiredSize,
196 const nsHTMLReflowState& aReflowState,
197 nscoord aX,
198 nscoord aY,
199 uint32_t aFlags,
200 nsReflowStatus& aStatus,
201 nsOverflowContinuationTracker* aTracker = nullptr);
202
203 /**
204 * The second half of frame reflow. Does the following:
205 * - sets the frame's bounds
206 * - sizes and positions (if requested) the frame's view. If the frame's final
207 * position differs from the current position and the frame itself does not
208 * have a view, then any child frames with views are positioned so they stay
209 * in sync
210 * - sets the view's visibility, opacity, content transparency, and clip
211 * - invoked the DidReflow() function
212 *
213 * Flags:
214 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
215 * case. Also implies NS_FRAME_NO_MOVE_VIEW
216 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
217 * don't want to automatically sync the frame and view
218 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
219 */
220 static nsresult FinishReflowChild(nsIFrame* aKidFrame,
221 nsPresContext* aPresContext,
222 const nsHTMLReflowMetrics& aDesiredSize,
223 const nsHTMLReflowState* aReflowState,
224 nscoord aX,
225 nscoord aY,
226 uint32_t aFlags);
227
228
229 static void PositionChildViews(nsIFrame* aFrame);
230
231 // ==========================================================================
232 /* Overflow containers are continuation frames that hold overflow. They
233 * are created when the frame runs out of computed height, but still has
234 * too much content to fit in the availableHeight. The parent creates a
235 * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
236 * and adds it to its next-in-flow's overflow container list, either by
237 * adding it directly or by putting it in its own excess overflow containers
238 * list (to be drained by the next-in-flow when it calls
239 * ReflowOverflowContainerChildren). The parent continues reflow as if
240 * the frame was complete once it ran out of computed height, but returns
241 * either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
242 * status to request a next-in-flow. The parent's next-in-flow is then
243 * responsible for calling ReflowOverflowContainerChildren to (drain and)
244 * reflow these overflow continuations. Overflow containers do not affect
245 * other frames' size or position during reflow (but do affect their
246 * parent's overflow area).
247 *
248 * Overflow container continuations are different from normal continuations
249 * in that
250 * - more than one child of the frame can have its next-in-flow broken
251 * off and pushed into the frame's next-in-flow
252 * - new continuations may need to be spliced into the middle of the list
253 * or deleted continuations slipped out
254 * e.g. A, B, C are all fixed-size containers on one page, all have
255 * overflow beyond availableHeight, and content is dynamically added
256 * and removed from B
257 * As a result, it is not possible to simply prepend the new continuations
258 * to the old list as with the overflowProperty mechanism. To avoid
259 * complicated list splicing, the code assumes only one overflow containers
260 * list exists for a given frame: either its own overflowContainersProperty
261 * or its prev-in-flow's excessOverflowContainersProperty, not both.
262 *
263 * The nsOverflowContinuationTracker helper class should be used for tracking
264 * overflow containers and adding them to the appropriate list.
265 * See nsBlockFrame::Reflow for a sample implementation.
266 */
267
268 friend class nsOverflowContinuationTracker;
269
270 /**
271 * Reflow overflow container children. They are invisible to normal reflow
272 * (i.e. don't affect sizing or placement of other children) and inherit
273 * width and horizontal position from their prev-in-flow.
274 *
275 * This method
276 * 1. Pulls excess overflow containers from the prev-in-flow and adds
277 * them to our overflow container list
278 * 2. Reflows all our overflow container kids
279 * 3. Expands aOverflowRect as necessary to accomodate these children.
280 * 4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
281 * NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
282 * are incomplete and
283 * 5. Prepends a list of their continuations to our excess overflow
284 * container list, to be drained into our next-in-flow when it is
285 * reflowed.
286 *
287 * The caller is responsible for tracking any new overflow container
288 * continuations it makes, removing them from its child list, and
289 * making sure they are stored properly in the overflow container lists.
290 * The nsOverflowContinuationTracker helper class should be used for this.
291 *
292 * (aFlags just gets passed through to ReflowChild)
293 */
294 nsresult ReflowOverflowContainerChildren(nsPresContext* aPresContext,
295 const nsHTMLReflowState& aReflowState,
296 nsOverflowAreas& aOverflowRects,
297 uint32_t aFlags,
298 nsReflowStatus& aStatus);
299
300 /**
301 * Move any frames on our overflow list to the end of our principal list.
302 * @return true if there were any overflow frames
303 */
304 virtual bool DrainSelfOverflowList() MOZ_OVERRIDE;
305
306 /**
307 * Removes aChild without destroying it and without requesting reflow.
308 * Continuations are not affected. Checks the primary and overflow
309 * or overflow containers and excess overflow containers lists, depending
310 * on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
311 * check any other auxiliary lists.
312 * Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
313 * Returns other error codes if we failed to put back a proptable list.
314 * If aForceNormal is true, only checks the primary and overflow lists
315 * even when the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set.
316 */
317 virtual nsresult StealFrame(nsIFrame* aChild,
318 bool aForceNormal = false);
319
320 /**
321 * Removes the next-siblings of aChild without destroying them and without
322 * requesting reflow. Checks the principal and overflow lists (not
323 * overflow containers / excess overflow containers). Does not check any
324 * other auxiliary lists.
325 * @param aChild a child frame or nullptr
326 * @return If aChild is non-null, the next-siblings of aChild, if any.
327 * If aChild is null, all child frames on the principal list, if any.
328 */
329 nsFrameList StealFramesAfter(nsIFrame* aChild);
330
331 /**
332 * Add overflow containers to the display list
333 */
334 void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
335 const nsRect& aDirtyRect,
336 const nsDisplayListSet& aLists);
337
338 /**
339 * Builds display lists for the children. The background
340 * of each child is placed in the Content() list (suitable for inline
341 * children and other elements that behave like inlines,
342 * but not for in-flow block children of blocks). DOES NOT
343 * paint the background/borders/outline of this frame. This should
344 * probably be avoided and eventually removed. It's currently here
345 * to emulate what nsContainerFrame::Paint did.
346 */
347 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
348 const nsRect& aDirtyRect,
349 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
350
351 /**
352 * Destructor function for the proptable-stored framelists --
353 * it should never be called.
354 */
355 static void DestroyFrameList(void* aPropertyValue)
356 {
357 MOZ_ASSERT(false, "The owning frame should destroy its nsFrameList props");
358 }
359
360 static void PlaceFrameView(nsIFrame* aFrame)
361 {
362 if (aFrame->HasView())
363 nsContainerFrame::PositionFrameView(aFrame);
364 else
365 nsContainerFrame::PositionChildViews(aFrame);
366 }
367
368 #define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
369 NS_DECLARE_FRAME_PROPERTY(prop, nsContainerFrame::DestroyFrameList)
370
371 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
372 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
373 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
374
375 protected:
376 nsContainerFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
377 ~nsContainerFrame();
378
379 /**
380 * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
381 * destroying frames on lists that can contain placeholders.
382 * Derived classes must do that too, if they destroy such frame lists.
383 * See nsBlockFrame::DestroyFrom for an example.
384 */
385 void DestroyAbsoluteFrames(nsIFrame* aDestructRoot);
386
387 /**
388 * Builds a display list for non-block children that behave like
389 * inlines. This puts the background of each child into the
390 * Content() list (suitable for inline children but not for
391 * in-flow block children of blocks).
392 * @param aForcePseudoStack forces each child into a pseudo-stacking-context
393 * so its background and all other display items (except for positioned
394 * display items) go into the Content() list.
395 */
396 void BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
397 const nsRect& aDirtyRect,
398 const nsDisplayListSet& aLists,
399 uint32_t aFlags = 0);
400
401 /**
402 * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
403 * Intended as a convenience for derived classes.
404 */
405 void BuildDisplayListForInline(nsDisplayListBuilder* aBuilder,
406 const nsRect& aDirtyRect,
407 const nsDisplayListSet& aLists) {
408 DisplayBorderBackgroundOutline(aBuilder, aLists);
409 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
410 DISPLAY_CHILD_INLINE);
411 }
412
413
414 // ==========================================================================
415 /* Overflow Frames are frames that did not fit and must be pulled by
416 * our next-in-flow during its reflow. (The same concept for overflow
417 * containers is called "excess frames". We should probably make the
418 * names match.)
419 */
420
421 /**
422 * Get the frames on the overflow list. Can return null if there are no
423 * overflow frames. The caller does NOT take ownership of the list; it's
424 * still owned by this frame. A non-null return value indicates that the
425 * list is nonempty.
426 */
427 inline nsFrameList* GetOverflowFrames() const;
428
429 /**
430 * As GetOverflowFrames, but removes the overflow frames property. The
431 * caller is responsible for deleting nsFrameList and either passing
432 * ownership of the frames to someone else or destroying the frames.
433 * A non-null return value indicates that the list is nonempty. The
434 * recommended way to use this function it to assign its return value
435 * into an AutoFrameListPtr.
436 */
437 inline nsFrameList* StealOverflowFrames();
438
439 /**
440 * Set the overflow list. aOverflowFrames must not be an empty list.
441 */
442 void SetOverflowFrames(const nsFrameList& aOverflowFrames);
443
444 /**
445 * Destroy the overflow list, which must be empty.
446 */
447 inline void DestroyOverflowList();
448
449 /**
450 * Moves any frames on both the prev-in-flow's overflow list and the
451 * receiver's overflow to the receiver's child list.
452 *
453 * Resets the overlist pointers to nullptr, and updates the receiver's child
454 * count and content mapping.
455 *
456 * @return true if any frames were moved and false otherwise
457 */
458 bool MoveOverflowToChildList();
459
460 /**
461 * Push aFromChild and its next siblings to the next-in-flow. Change
462 * the geometric parent of each frame that's pushed. If there is no
463 * next-in-flow the frames are placed on the overflow list (and the
464 * geometric parent is left unchanged).
465 *
466 * Updates the next-in-flow's child count. Does <b>not</b> update the
467 * pusher's child count.
468 *
469 * @param aFromChild the first child frame to push. It is disconnected from
470 * aPrevSibling
471 * @param aPrevSibling aFromChild's previous sibling. Must not be null.
472 * It's an error to push a parent's first child frame
473 */
474 void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
475
476 // ==========================================================================
477 /*
478 * Convenience methods for nsFrameLists stored in the
479 * PresContext's proptable
480 */
481
482 /**
483 * Get the PresContext-stored nsFrameList named aPropID for this frame.
484 * May return null.
485 */
486 nsFrameList* GetPropTableFrames(const FramePropertyDescriptor* aProperty) const;
487
488 /**
489 * Remove and return the PresContext-stored nsFrameList named aPropID for
490 * this frame. May return null.
491 */
492 nsFrameList* RemovePropTableFrames(const FramePropertyDescriptor* aProperty);
493
494 /**
495 * Set the PresContext-stored nsFrameList named aPropID for this frame
496 * to the given aFrameList, which must not be null.
497 */
498 void SetPropTableFrames(nsFrameList* aFrameList,
499 const FramePropertyDescriptor* aProperty);
500
501 /**
502 * Safely destroy the frames on the nsFrameList stored on aProp for this
503 * frame then remove the property and delete the frame list.
504 * Nothing happens if the property doesn't exist.
505 */
506 void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
507 nsIPresShell* aPresShell,
508 mozilla::FramePropertyTable* aPropTable,
509 const FramePropertyDescriptor* aProp);
510
511 // ==========================================================================
512
513 nsFrameList mFrames;
514 };
515
516 // ==========================================================================
517 /* The out-of-flow-related code below is for a hacky way of splitting
518 * absolutely-positioned frames. Basically what we do is split the frame
519 * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
520 * container. This isn't an ideal solution, but it lets us print the content
521 * at least. See bug 154892.
522 */
523
524 #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
525 ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
526 && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
527 frame->IsAbsolutelyPositioned() ) )
528 //XXXfr This check isn't quite correct, because it doesn't handle cases
529 // where the out-of-flow has overflow.. but that's rare.
530 // We'll need to revisit the way abspos continuations are handled later
531 // for various reasons, this detail is one of them. See bug 154892
532
533 /**
534 * Helper class for tracking overflow container continuations during reflow.
535 *
536 * A frame is related to two sets of overflow containers: those that /are/
537 * its own children, and those that are /continuations/ of its children.
538 * This tracker walks through those continuations (the frame's NIF's children)
539 * and their prev-in-flows (a subset of the frame's normal and overflow
540 * container children) in parallel. It allows the reflower to synchronously
541 * walk its overflow continuations while it loops through and reflows its
542 * children. This makes it possible to insert new continuations at the correct
543 * place in the overflow containers list.
544 *
545 * The reflower is expected to loop through its children in the same order it
546 * looped through them the last time (if there was a last time).
547 * For each child, the reflower should either
548 * - call Skip for the child if was not reflowed in this pass
549 * - call Insert for the overflow continuation if the child was reflowed
550 * but has incomplete overflow
551 * - call Finished for the child if it was reflowed in this pass but
552 * is either complete or has a normal next-in-flow. This call can
553 * be skipped if the child did not previously have an overflow
554 * continuation.
555 */
556 class nsOverflowContinuationTracker {
557 public:
558 /**
559 * Initializes an nsOverflowContinuationTracker to help track overflow
560 * continuations of aFrame's children. Typically invoked on 'this'.
561 *
562 * aWalkOOFFrames determines whether the walker skips out-of-flow frames
563 * or skips non-out-of-flow frames.
564 *
565 * Don't set aSkipOverflowContainerChildren to false unless you plan
566 * to walk your own overflow container children. (Usually they are handled
567 * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
568 * if aSkipOverflowContainerChildren is false.
569 */
570 nsOverflowContinuationTracker(nsContainerFrame* aFrame,
571 bool aWalkOOFFrames,
572 bool aSkipOverflowContainerChildren = true);
573 /**
574 * This function adds an overflow continuation to our running list and
575 * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
576 *
577 * aReflowStatus should preferably be specific to the recently-reflowed
578 * child and not influenced by any of its siblings' statuses. This
579 * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
580 * to be reflowed. (Its need for reflow depends on changes to its
581 * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
582 *
583 * The caller MUST disconnect the frame from its parent's child list
584 * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
585 * StealFrame is much more inefficient than disconnecting in place
586 * during Reflow, which the caller is able to do but we are not).
587 *
588 * The caller MUST NOT disconnect the frame from its parent's
589 * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
590 * (In this case we will disconnect and reconnect it ourselves.)
591 */
592 nsresult Insert(nsIFrame* aOverflowCont,
593 nsReflowStatus& aReflowStatus);
594 /**
595 * Begin/EndFinish() must be called for each child that is reflowed
596 * but no longer has an overflow continuation. (It may be called for
597 * other children, but in that case has no effect.) It increments our
598 * walker and makes sure we drop any dangling pointers to its
599 * next-in-flow. This function MUST be called before stealing or
600 * deleting aChild's next-in-flow.
601 * The AutoFinish helper object does that for you. Use it like so:
602 * if (kidNextInFlow) {
603 * nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
604 * ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
605 * }
606 */
607 class MOZ_STACK_CLASS AutoFinish {
608 public:
609 AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
610 : mTracker(aTracker), mChild(aChild)
611 {
612 if (mTracker) mTracker->BeginFinish(mChild);
613 }
614 ~AutoFinish()
615 {
616 if (mTracker) mTracker->EndFinish(mChild);
617 }
618 private:
619 nsOverflowContinuationTracker* mTracker;
620 nsIFrame* mChild;
621 };
622
623 /**
624 * This function should be called for each child that isn't reflowed.
625 * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
626 * reflow flag if it encounters an overflow continuation so that our
627 * next-in-flow doesn't get prematurely deleted. It MUST be called on
628 * each unreflowed child that has an overflow container continuation;
629 * it MAY be called on other children, but it isn't necessary (doesn't
630 * do anything).
631 */
632 void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
633 {
634 NS_PRECONDITION(aChild, "null ptr");
635 if (aChild == mSentry) {
636 StepForward();
637 NS_MergeReflowStatusInto(&aReflowStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
638 }
639 }
640
641 private:
642
643 /**
644 * @see class AutoFinish
645 */
646 void BeginFinish(nsIFrame* aChild);
647 void EndFinish(nsIFrame* aChild);
648
649 void SetupOverflowContList();
650 void SetUpListWalker();
651 void StepForward();
652
653 /* We hold a pointer to either the next-in-flow's overflow containers list
654 or, if that doesn't exist, our frame's excess overflow containers list.
655 We need to make sure that we drop that pointer if the list becomes
656 empty and is deleted elsewhere. */
657 nsFrameList* mOverflowContList;
658 /* We hold a pointer to the most recently-reflowed child that has an
659 overflow container next-in-flow. We do this because it's a known
660 good point; this pointer won't be deleted on us. We can use it to
661 recover our place in the list. */
662 nsIFrame* mPrevOverflowCont;
663 /* This is a pointer to the next overflow container's prev-in-flow, which
664 is (or should be) a child of our frame. When we hit this, we will need
665 to increment this walker to the next overflow container. */
666 nsIFrame* mSentry;
667 /* Parent of all frames in mOverflowContList. If our mOverflowContList
668 is an excessOverflowContainersProperty, or null, then this is our frame
669 (the frame that was passed in to our constructor). Otherwise this is
670 that frame's next-in-flow, and our mOverflowContList is mParent's
671 overflowContainersProperty */
672 nsContainerFrame* mParent;
673 /* Tells SetUpListWalker whether or not to walk us past any continuations
674 of overflow containers. aWalkOOFFrames is ignored when this is false. */
675 bool mSkipOverflowContainerChildren;
676 /* Tells us whether to pay attention to OOF frames or non-OOF frames */
677 bool mWalkOOFFrames;
678 };
679
680 inline
681 nsFrameList*
682 nsContainerFrame::GetOverflowFrames() const
683 {
684 nsFrameList* list =
685 static_cast<nsFrameList*>(Properties().Get(OverflowProperty()));
686 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
687 return list;
688 }
689
690 inline
691 nsFrameList*
692 nsContainerFrame::StealOverflowFrames()
693 {
694 nsFrameList* list =
695 static_cast<nsFrameList*>(Properties().Remove(OverflowProperty()));
696 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
697 return list;
698 }
699
700 inline void
701 nsContainerFrame::DestroyOverflowList()
702 {
703 nsFrameList* list = RemovePropTableFrames(OverflowProperty());
704 MOZ_ASSERT(list && list->IsEmpty());
705 list->Delete(PresContext()->PresShell());
706 }
707
708 #endif /* nsContainerFrame_h___ */

mercurial