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