Bug 1474771 - Revert all changes from bug 1459937 since they are no longer needed...
[gecko.git] / layout / generic / nsContainerFrame.h
blobf2ef0a86dbeb6394b14ba1ef5a1664a4f83f3b6c
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/. */
7 /* base class #1 for rendering objects that have child lists */
9 #ifndef nsContainerFrame_h___
10 #define nsContainerFrame_h___
12 #include "mozilla/Attributes.h"
13 #include "nsSplittableFrame.h"
14 #include "nsFrameList.h"
15 #include "nsLayoutUtils.h"
17 // Option flags for ReflowChild() and FinishReflowChild()
18 // member functions
19 #define NS_FRAME_NO_MOVE_VIEW 0x0001
20 #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
21 #define NS_FRAME_NO_SIZE_VIEW 0x0004
22 #define NS_FRAME_NO_VISIBILITY 0x0008
23 // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
24 // if the reflow is fully complete.
25 #define NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD 0x0010
27 class nsOverflowContinuationTracker;
29 namespace mozilla {
30 class PresShell;
31 } // namespace mozilla
33 // Some macros for container classes to do sanity checking on
34 // width/height/x/y values computed during reflow.
35 // NOTE: AppUnitsPerCSSPixel value hardwired here to remove the
36 // dependency on nsDeviceContext.h. It doesn't matter if it's a
37 // little off.
38 #ifdef DEBUG
39 // 10 million pixels, converted to app units. Note that this a bit larger
40 // than 1/4 of nscoord_MAX. So, if any content gets to be this large, we're
41 // definitely in danger of grazing up against nscoord_MAX; hence, it's CRAZY.
42 # define CRAZY_COORD (10000000 * 60)
43 # define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
44 #endif
46 /**
47 * Implementation of a container frame.
49 class nsContainerFrame : public nsSplittableFrame {
50 public:
51 NS_DECL_ABSTRACT_FRAME(nsContainerFrame)
52 NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
53 NS_DECL_QUERYFRAME
55 // nsIFrame overrides
56 virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
57 nsIFrame* aPrevInFlow) override;
58 virtual nsContainerFrame* GetContentInsertionFrame() override { return this; }
60 virtual const nsFrameList& GetChildList(ChildListID aList) const override;
61 virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
62 virtual void DestroyFrom(nsIFrame* aDestructRoot,
63 PostDestroyData& aPostDestroyData) override;
64 virtual void ChildIsDirty(nsIFrame* aChild) override;
66 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward,
67 int32_t* aOffset) override;
68 virtual FrameSearchResult PeekOffsetCharacter(
69 bool aForward, int32_t* aOffset,
70 PeekOffsetCharacterOptions aOptions =
71 PeekOffsetCharacterOptions()) override;
73 #ifdef DEBUG_FRAME_DUMP
74 void List(FILE* out = stderr, const char* aPrefix = "",
75 uint32_t aFlags = 0) const override;
76 void ListWithMatchedRules(FILE* out = stderr,
77 const char* aPrefix = "") const override;
78 #endif
80 // nsContainerFrame methods
82 /**
83 * Called to set the initial list of frames. This happens after the frame
84 * has been initialized.
86 * This is only called once for a given child list, and won't be called
87 * at all for child lists with no initial list of frames.
89 * @param aListID the child list identifier.
90 * @param aChildList list of child frames. Each of the frames has its
91 * NS_FRAME_IS_DIRTY bit set. Must not be empty.
92 * This method cannot handle the child list returned by
93 * GetAbsoluteListID().
94 * @see #Init()
96 virtual void SetInitialChildList(ChildListID aListID,
97 nsFrameList& aChildList);
99 /**
100 * This method is responsible for appending frames to the frame
101 * list. The implementation should append the frames to the specified
102 * child list and then generate a reflow command.
104 * @param aListID the child list identifier.
105 * @param aFrameList list of child frames to append. Each of the frames has
106 * its NS_FRAME_IS_DIRTY bit set. Must not be empty.
108 virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList);
111 * This method is responsible for inserting frames into the frame
112 * list. The implementation should insert the new frames into the specified
113 * child list and then generate a reflow command.
115 * @param aListID the child list identifier.
116 * @param aPrevFrame the frame to insert frames <b>after</b>
117 * @param aFrameList list of child frames to insert <b>after</b> aPrevFrame.
118 * Each of the frames has its NS_FRAME_IS_DIRTY bit set
120 virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
121 nsFrameList& aFrameList);
124 * This method is responsible for removing a frame in the frame
125 * list. The implementation should do something with the removed frame
126 * and then generate a reflow command. The implementation is responsible
127 * for destroying aOldFrame (the caller mustn't destroy aOldFrame).
129 * @param aListID the child list identifier.
130 * @param aOldFrame the frame to remove
132 virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
135 * Helper method to create next-in-flows if necessary. If aFrame
136 * already has a next-in-flow then this method does
137 * nothing. Otherwise, a new continuation frame is created and
138 * linked into the flow. In addition, the new frame is inserted
139 * into the principal child list after aFrame.
140 * @note calling this method on a block frame is illegal. Use
141 * nsBlockFrame::CreateContinuationFor() instead.
142 * @return the next-in-flow <b>if and only if</b> one is created. If
143 * a next-in-flow already exists, nullptr will be returned.
145 nsIFrame* CreateNextInFlow(nsIFrame* aFrame);
148 * Delete aNextInFlow and its next-in-flows.
149 * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
150 * content was complete before aNextInFlow, so aNextInFlow and its
151 * next-in-flows no longer map any real content.
153 virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow,
154 bool aDeletingEmptyFrames);
156 // Positions the frame's view based on the frame's origin
157 static void PositionFrameView(nsIFrame* aKidFrame);
159 static nsresult ReparentFrameView(nsIFrame* aChildFrame,
160 nsIFrame* aOldParentFrame,
161 nsIFrame* aNewParentFrame);
163 static nsresult ReparentFrameViewList(const nsFrameList& aChildFrameList,
164 nsIFrame* aOldParentFrame,
165 nsIFrame* aNewParentFrame);
167 // Set the view's size and position after its frame has been reflowed.
169 // Flags:
170 // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
171 // don't want to automatically sync the frame and view
172 // NS_FRAME_NO_SIZE_VIEW - don't size the view
173 static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
174 nsIFrame* aFrame, nsView* aView,
175 const nsRect& aVisualOverflowArea,
176 uint32_t aFlags = 0);
178 // Syncs properties to the top level view and window, like transparency and
179 // shadow.
180 // The SET_ASYNC indicates that the actual nsIWidget calls to sync the window
181 // properties should be done async.
182 enum {
183 SET_ASYNC = 0x01,
185 static void SyncWindowProperties(nsPresContext* aPresContext,
186 nsIFrame* aFrame, nsView* aView,
187 gfxContext* aRC, uint32_t aFlags);
190 * Converts the minimum and maximum sizes given in inner window app units to
191 * outer window device pixel sizes and assigns these constraints to the
192 * widget.
194 * @param aPresContext pres context
195 * @param aWidget widget for this frame
196 * @param minimum size of the window in app units
197 * @param maxmimum size of the window in app units
199 static void SetSizeConstraints(nsPresContext* aPresContext,
200 nsIWidget* aWidget, const nsSize& aMinSize,
201 const nsSize& aMaxSize);
203 // Used by both nsInlineFrame and nsFirstLetterFrame.
204 void DoInlineIntrinsicISize(gfxContext* aRenderingContext,
205 InlineIntrinsicISizeData* aData,
206 nsLayoutUtils::IntrinsicISizeType aType);
209 * This is the CSS block concept of computing 'auto' widths, which most
210 * classes derived from nsContainerFrame want.
212 virtual mozilla::LogicalSize ComputeAutoSize(
213 gfxContext* aRenderingContext, mozilla::WritingMode aWM,
214 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
215 const mozilla::LogicalSize& aMargin, const mozilla::LogicalSize& aBorder,
216 const mozilla::LogicalSize& aPadding, ComputeSizeFlags aFlags) override;
219 * Positions aChildFrame and its view (if requested), and then calls Reflow().
220 * If the reflow status after reflowing the child is FULLY_COMPLETE then any
221 * next-in-flows are deleted using DeleteNextInFlowChild().
223 * @param aContainerSize size of the border-box of the containing frame
225 * Flags:
226 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
227 * don't want to automatically sync the frame and view
228 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aPos is ignored in this
229 * case. Also implies NS_FRAME_NO_MOVE_VIEW
231 void ReflowChild(nsIFrame* aChildFrame, nsPresContext* aPresContext,
232 ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput,
233 const mozilla::WritingMode& aWM,
234 const mozilla::LogicalPoint& aPos,
235 const nsSize& aContainerSize, uint32_t aFlags,
236 nsReflowStatus& aStatus,
237 nsOverflowContinuationTracker* aTracker = nullptr);
240 * The second half of frame reflow. Does the following:
241 * - sets the frame's bounds
242 * - sizes and positions (if requested) the frame's view. If the frame's final
243 * position differs from the current position and the frame itself does not
244 * have a view, then any child frames with views are positioned so they stay
245 * in sync
246 * - sets the view's visibility, opacity, content transparency, and clip
247 * - invoked the DidReflow() function
249 * @param aContainerSize size of the border-box of the containing frame
251 * Flags:
252 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aPos is ignored in this
253 * case. Also implies NS_FRAME_NO_MOVE_VIEW
254 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
255 * don't want to automatically sync the frame and view
256 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
258 static void FinishReflowChild(nsIFrame* aKidFrame,
259 nsPresContext* aPresContext,
260 const ReflowOutput& aDesiredSize,
261 const ReflowInput* aReflowInput,
262 const mozilla::WritingMode& aWM,
263 const mozilla::LogicalPoint& aPos,
264 const nsSize& aContainerSize, uint32_t aFlags);
266 // XXX temporary: hold on to a copy of the old physical versions of
267 // ReflowChild and FinishReflowChild so that we can convert callers
268 // incrementally.
269 void ReflowChild(nsIFrame* aKidFrame, nsPresContext* aPresContext,
270 ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput,
271 nscoord aX, nscoord aY, uint32_t aFlags,
272 nsReflowStatus& aStatus,
273 nsOverflowContinuationTracker* aTracker = nullptr);
275 static void FinishReflowChild(nsIFrame* aKidFrame,
276 nsPresContext* aPresContext,
277 const ReflowOutput& aDesiredSize,
278 const ReflowInput* aReflowInput, nscoord aX,
279 nscoord aY, uint32_t aFlags);
281 static void PositionChildViews(nsIFrame* aFrame);
283 // ==========================================================================
284 /* Overflow containers are continuation frames that hold overflow. They
285 * are created when the frame runs out of computed height, but still has
286 * too much content to fit in the availableHeight. The parent creates a
287 * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
288 * and adds it to its next-in-flow's overflow container list, either by
289 * adding it directly or by putting it in its own excess overflow containers
290 * list (to be drained by the next-in-flow when it calls
291 * ReflowOverflowContainerChildren). The parent continues reflow as if
292 * the frame was complete once it ran out of computed height, but returns a
293 * reflow status with either IsIncomplete() or IsOverflowIncomplete() equal
294 * to true to request a next-in-flow. The parent's next-in-flow is then
295 * responsible for calling ReflowOverflowContainerChildren to (drain and)
296 * reflow these overflow continuations. Overflow containers do not affect
297 * other frames' size or position during reflow (but do affect their
298 * parent's overflow area).
300 * Overflow container continuations are different from normal continuations
301 * in that
302 * - more than one child of the frame can have its next-in-flow broken
303 * off and pushed into the frame's next-in-flow
304 * - new continuations may need to be spliced into the middle of the list
305 * or deleted continuations slipped out
306 * e.g. A, B, C are all fixed-size containers on one page, all have
307 * overflow beyond availableHeight, and content is dynamically added
308 * and removed from B
309 * As a result, it is not possible to simply prepend the new continuations
310 * to the old list as with the overflowProperty mechanism. To avoid
311 * complicated list splicing, the code assumes only one overflow containers
312 * list exists for a given frame: either its own overflowContainersProperty
313 * or its prev-in-flow's excessOverflowContainersProperty, not both.
315 * The nsOverflowContinuationTracker helper class should be used for tracking
316 * overflow containers and adding them to the appropriate list.
317 * See nsBlockFrame::Reflow for a sample implementation.
320 friend class nsOverflowContinuationTracker;
322 typedef void (*ChildFrameMerger)(nsFrameList& aDest, nsFrameList& aSrc,
323 nsContainerFrame* aParent);
324 static inline void DefaultChildFrameMerge(nsFrameList& aDest,
325 nsFrameList& aSrc,
326 nsContainerFrame* aParent) {
327 aDest.AppendFrames(nullptr, aSrc);
331 * Reflow overflow container children. They are invisible to normal reflow
332 * (i.e. don't affect sizing or placement of other children) and inherit
333 * width and horizontal position from their prev-in-flow.
335 * This method
336 * 1. Pulls excess overflow containers from the prev-in-flow and adds
337 * them to our overflow container list
338 * 2. Reflows all our overflow container kids
339 * 3. Expands aOverflowRect as necessary to accomodate these children.
340 * 4. Sets aStatus's mOverflowIncomplete flag (along with
341 * mNextInFlowNeedsReflow as necessary) if any overflow children
342 * are incomplete and
343 * 5. Prepends a list of their continuations to our excess overflow
344 * container list, to be drained into our next-in-flow when it is
345 * reflowed.
347 * The caller is responsible for tracking any new overflow container
348 * continuations it makes, removing them from its child list, and
349 * making sure they are stored properly in the overflow container lists.
350 * The nsOverflowContinuationTracker helper class should be used for this.
352 * @param aFlags is passed through to ReflowChild
353 * @param aMergeFunc is passed to DrainExcessOverflowContainersList
355 void ReflowOverflowContainerChildren(
356 nsPresContext* aPresContext, const ReflowInput& aReflowInput,
357 nsOverflowAreas& aOverflowRects, uint32_t aFlags, nsReflowStatus& aStatus,
358 ChildFrameMerger aMergeFunc = DefaultChildFrameMerge);
361 * Move any frames on our overflow list to the end of our principal list.
362 * @return true if there were any overflow frames
364 virtual bool DrainSelfOverflowList() override;
367 * Move all frames on our prev-in-flow's and our own ExcessOverflowContainers
368 * lists to our OverflowContainers list. If there are frames on multiple
369 * lists they are merged using aMergeFunc.
370 * @return a pointer to our OverflowContainers list, if any
372 nsFrameList* DrainExcessOverflowContainersList(
373 ChildFrameMerger aMergeFunc = DefaultChildFrameMerge);
376 * Removes aChild without destroying it and without requesting reflow.
377 * Continuations are not affected. Checks the principal and overflow lists,
378 * and also the [excess] overflow containers lists if the frame bit
379 * NS_FRAME_IS_OVERFLOW_CONTAINER is set. It does not check any other lists.
380 * Returns NS_ERROR_UNEXPECTED if aChild wasn't found on any of the lists
381 * mentioned above.
383 virtual nsresult StealFrame(nsIFrame* aChild);
386 * Removes the next-siblings of aChild without destroying them and without
387 * requesting reflow. Checks the principal and overflow lists (not
388 * overflow containers / excess overflow containers). Does not check any
389 * other auxiliary lists.
390 * @param aChild a child frame or nullptr
391 * @return If aChild is non-null, the next-siblings of aChild, if any.
392 * If aChild is null, all child frames on the principal list, if any.
394 nsFrameList StealFramesAfter(nsIFrame* aChild);
397 * Add overflow containers to the display list
399 void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
400 const nsDisplayListSet& aLists);
403 * Builds display lists for the children. The background
404 * of each child is placed in the Content() list (suitable for inline
405 * children and other elements that behave like inlines,
406 * but not for in-flow block children of blocks). DOES NOT
407 * paint the background/borders/outline of this frame. This should
408 * probably be avoided and eventually removed. It's currently here
409 * to emulate what nsContainerFrame::Paint did.
411 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
412 const nsDisplayListSet& aLists) override;
414 static void PlaceFrameView(nsIFrame* aFrame) {
415 if (aFrame->HasView())
416 nsContainerFrame::PositionFrameView(aFrame);
417 else
418 nsContainerFrame::PositionChildViews(aFrame);
422 * Returns a CSS Box Alignment constant which the caller can use to align
423 * the absolutely-positioned child (whose ReflowInput is aChildRI) within
424 * a CSS Box Alignment area associated with this container.
426 * The lower 8 bits of the returned value are guaranteed to form a valid
427 * argument for CSSAlignUtils::AlignJustifySelf(). (The upper 8 bits may
428 * encode an <overflow-position>.)
430 * NOTE: This default nsContainerFrame implementation is a stub, and isn't
431 * meant to be called. Subclasses must provide their own implementations, if
432 * they use CSS Box Alignment to determine the static position of their
433 * absolutely-positioned children. (Though: if subclasses share enough code,
434 * maybe this nsContainerFrame impl should include some shared code.)
436 * @param aChildRI A ReflowInput for the positioned child frame that's being
437 * aligned.
438 * @param aLogicalAxis The axis (of this container frame) in which the caller
439 * would like to align the child frame.
441 virtual uint16_t CSSAlignmentForAbsPosChild(
442 const ReflowInput& aChildRI, mozilla::LogicalAxis aLogicalAxis) const;
444 #define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
445 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, nsFrameList)
447 typedef PropertyDescriptor<nsFrameList> FrameListPropertyDescriptor;
449 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
450 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
451 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
452 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(BackdropProperty)
454 // Only really used on nsBlockFrame instances, but the caller thinks it could
455 // have arbitrary nsContainerFrames.
456 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(FirstLetterProperty, nsIFrame)
458 void SetHasFirstLetterChild() { mHasFirstLetterChild = true; }
460 void ClearHasFirstLetterChild() { mHasFirstLetterChild = false; }
462 #ifdef DEBUG
463 // Use this to suppress the CRAZY_SIZE assertions.
464 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool)
465 bool IsCrazySizeAssertSuppressed() const {
466 return GetProperty(DebugReflowingWithInfiniteISize());
468 #endif
470 protected:
471 nsContainerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
472 ClassID aID)
473 : nsSplittableFrame(aStyle, aPresContext, aID) {}
475 ~nsContainerFrame();
478 * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
479 * destroying frames on lists that can contain placeholders.
480 * Derived classes must do that too, if they destroy such frame lists.
481 * See nsBlockFrame::DestroyFrom for an example.
483 void DestroyAbsoluteFrames(nsIFrame* aDestructRoot,
484 PostDestroyData& aPostDestroyData);
487 * Helper for StealFrame. Returns true if aChild was removed from its list.
489 bool MaybeStealOverflowContainerFrame(nsIFrame* aChild);
492 * Builds a display list for non-block children that behave like
493 * inlines. This puts the background of each child into the
494 * Content() list (suitable for inline children but not for
495 * in-flow block children of blocks).
496 * @param aForcePseudoStack forces each child into a pseudo-stacking-context
497 * so its background and all other display items (except for positioned
498 * display items) go into the Content() list.
500 void BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
501 const nsDisplayListSet& aLists,
502 uint32_t aFlags = 0);
505 * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
506 * Intended as a convenience for derived classes.
508 void BuildDisplayListForInline(nsDisplayListBuilder* aBuilder,
509 const nsDisplayListSet& aLists) {
510 DisplayBorderBackgroundOutline(aBuilder, aLists);
511 BuildDisplayListForNonBlockChildren(aBuilder, aLists, DISPLAY_CHILD_INLINE);
514 // ==========================================================================
515 /* Overflow Frames are frames that did not fit and must be pulled by
516 * our next-in-flow during its reflow. (The same concept for overflow
517 * containers is called "excess frames". We should probably make the
518 * names match.)
522 * Get the frames on the overflow list. Can return null if there are no
523 * overflow frames. The caller does NOT take ownership of the list; it's
524 * still owned by this frame. A non-null return value indicates that the
525 * list is nonempty.
527 inline nsFrameList* GetOverflowFrames() const;
530 * As GetOverflowFrames, but removes the overflow frames property. The
531 * caller is responsible for deleting nsFrameList and either passing
532 * ownership of the frames to someone else or destroying the frames.
533 * A non-null return value indicates that the list is nonempty. The
534 * recommended way to use this function it to assign its return value
535 * into an AutoFrameListPtr.
537 inline nsFrameList* StealOverflowFrames();
540 * Set the overflow list. aOverflowFrames must not be an empty list.
542 void SetOverflowFrames(const nsFrameList& aOverflowFrames);
545 * Destroy the overflow list, which must be empty.
547 inline void DestroyOverflowList();
550 * Moves any frames on both the prev-in-flow's overflow list and the
551 * receiver's overflow to the receiver's child list.
553 * Resets the overlist pointers to nullptr, and updates the receiver's child
554 * count and content mapping.
556 * @return true if any frames were moved and false otherwise
558 bool MoveOverflowToChildList();
561 * Basically same as MoveOverflowToChildList, except that this is for
562 * handling inline children where children of prev-in-flow can be
563 * pushed to overflow list even if a next-in-flow exists.
565 * @param aLineContainer the line container of the current frame.
567 * @return true if any frames were moved and false otherwise
569 bool MoveInlineOverflowToChildList(nsIFrame* aLineContainer);
572 * Push aFromChild and its next siblings to the overflow list.
574 * @param aFromChild the first child frame to push. It is disconnected
575 * from aPrevSibling
576 * @param aPrevSibling aFrameChild's previous sibling. Must not be null.
577 * It's an error to push a parent's first child frame.
579 void PushChildrenToOverflow(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
582 * Same as above, except that this pushes frames to the next-in-flow
583 * frame and changes the geometric parent of the pushed frames when
584 * there is a next-in-flow frame.
586 * Updates the next-in-flow's child count. Does <b>not</b> update the
587 * pusher's child count.
589 void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
592 * Reparent floats whose placeholders are inline descendants of aFrame from
593 * whatever block they're currently parented by to aOurBlock.
594 * @param aReparentSiblings if this is true, we follow aFrame's
595 * GetNextSibling chain reparenting them all
597 static void ReparentFloatsForInlineChild(nsIFrame* aOurBlock,
598 nsIFrame* aFrame,
599 bool aReparentSiblings);
601 // ==========================================================================
603 * Convenience methods for traversing continuations
606 struct ContinuationTraversingState {
607 nsContainerFrame* mNextInFlow;
608 explicit ContinuationTraversingState(nsContainerFrame* aFrame)
609 : mNextInFlow(static_cast<nsContainerFrame*>(aFrame->GetNextInFlow())) {
614 * Find the first frame that is a child of this frame's next-in-flows,
615 * considering both their principal child lists and overflow lists.
617 nsIFrame* GetNextInFlowChild(ContinuationTraversingState& aState,
618 bool* aIsInOverflow = nullptr);
621 * Remove the result of GetNextInFlowChild from its current parent and
622 * append it to this frame's principal child list.
624 nsIFrame* PullNextInFlowChild(ContinuationTraversingState& aState);
626 // ==========================================================================
628 * Convenience methods for nsFrameLists stored in the
629 * PresContext's proptable
633 * Get the PresContext-stored nsFrameList named aPropID for this frame.
634 * May return null.
636 nsFrameList* GetPropTableFrames(FrameListPropertyDescriptor aProperty) const;
639 * Remove and return the PresContext-stored nsFrameList named aPropID for
640 * this frame. May return null.
642 nsFrameList* RemovePropTableFrames(FrameListPropertyDescriptor aProperty);
645 * Set the PresContext-stored nsFrameList named aPropID for this frame
646 * to the given aFrameList, which must not be null.
648 void SetPropTableFrames(nsFrameList* aFrameList,
649 FrameListPropertyDescriptor aProperty);
652 * Safely destroy the frames on the nsFrameList stored on aProp for this
653 * frame then remove the property and delete the frame list.
654 * Nothing happens if the property doesn't exist.
656 void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
657 PostDestroyData& aPostDestroyData,
658 mozilla::PresShell* aPresShell,
659 FrameListPropertyDescriptor aProp);
661 // ==========================================================================
663 // Helper used by Progress and Meter frames. Returns true if the bar should
664 // be rendered vertically, based on writing-mode and -moz-orient properties.
665 bool ResolvedOrientationIsVertical();
667 // ==========================================================================
669 nsFrameList mFrames;
672 // ==========================================================================
673 /* The out-of-flow-related code below is for a hacky way of splitting
674 * absolutely-positioned frames. Basically what we do is split the frame
675 * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
676 * container. This isn't an ideal solution, but it lets us print the content
677 * at least. See bug 154892.
680 #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
681 ((frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) && \
682 !((frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
683 frame->IsAbsolutelyPositioned()))
684 // XXXfr This check isn't quite correct, because it doesn't handle cases
685 // where the out-of-flow has overflow.. but that's rare.
686 // We'll need to revisit the way abspos continuations are handled later
687 // for various reasons, this detail is one of them. See bug 154892
690 * Helper class for tracking overflow container continuations during reflow.
692 * A frame is related to two sets of overflow containers: those that /are/
693 * its own children, and those that are /continuations/ of its children.
694 * This tracker walks through those continuations (the frame's NIF's children)
695 * and their prev-in-flows (a subset of the frame's normal and overflow
696 * container children) in parallel. It allows the reflower to synchronously
697 * walk its overflow continuations while it loops through and reflows its
698 * children. This makes it possible to insert new continuations at the correct
699 * place in the overflow containers list.
701 * The reflower is expected to loop through its children in the same order it
702 * looped through them the last time (if there was a last time).
703 * For each child, the reflower should either
704 * - call Skip for the child if was not reflowed in this pass
705 * - call Insert for the overflow continuation if the child was reflowed
706 * but has incomplete overflow
707 * - call Finished for the child if it was reflowed in this pass but
708 * is either complete or has a normal next-in-flow. This call can
709 * be skipped if the child did not previously have an overflow
710 * continuation.
712 class nsOverflowContinuationTracker {
713 public:
715 * Initializes an nsOverflowContinuationTracker to help track overflow
716 * continuations of aFrame's children. Typically invoked on 'this'.
718 * aWalkOOFFrames determines whether the walker skips out-of-flow frames
719 * or skips non-out-of-flow frames.
721 * Don't set aSkipOverflowContainerChildren to false unless you plan
722 * to walk your own overflow container children. (Usually they are handled
723 * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
724 * if aSkipOverflowContainerChildren is false.
726 nsOverflowContinuationTracker(nsContainerFrame* aFrame, bool aWalkOOFFrames,
727 bool aSkipOverflowContainerChildren = true);
729 * This function adds an overflow continuation to our running list and
730 * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
732 * aReflowStatus should preferably be specific to the recently-reflowed
733 * child and not influenced by any of its siblings' statuses. This
734 * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
735 * to be reflowed. (Its need for reflow depends on changes to its
736 * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
738 * The caller MUST disconnect the frame from its parent's child list
739 * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
740 * StealFrame is much more inefficient than disconnecting in place
741 * during Reflow, which the caller is able to do but we are not).
743 * The caller MUST NOT disconnect the frame from its parent's
744 * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
745 * (In this case we will disconnect and reconnect it ourselves.)
747 nsresult Insert(nsIFrame* aOverflowCont, nsReflowStatus& aReflowStatus);
749 * Begin/EndFinish() must be called for each child that is reflowed
750 * but no longer has an overflow continuation. (It may be called for
751 * other children, but in that case has no effect.) It increments our
752 * walker and makes sure we drop any dangling pointers to its
753 * next-in-flow. This function MUST be called before stealing or
754 * deleting aChild's next-in-flow.
755 * The AutoFinish helper object does that for you. Use it like so:
756 * if (kidNextInFlow) {
757 * nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
758 * ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
761 class MOZ_RAII AutoFinish {
762 public:
763 AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
764 : mTracker(aTracker), mChild(aChild) {
765 if (mTracker) mTracker->BeginFinish(mChild);
767 ~AutoFinish() {
768 if (mTracker) mTracker->EndFinish(mChild);
771 private:
772 nsOverflowContinuationTracker* mTracker;
773 nsIFrame* mChild;
777 * This function should be called for each child that isn't reflowed.
778 * It increments our walker and sets the mOverflowIncomplete
779 * reflow flag if it encounters an overflow continuation so that our
780 * next-in-flow doesn't get prematurely deleted. It MUST be called on
781 * each unreflowed child that has an overflow container continuation;
782 * it MAY be called on other children, but it isn't necessary (doesn't
783 * do anything).
785 void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus) {
786 MOZ_ASSERT(aChild, "null ptr");
787 if (aChild == mSentry) {
788 StepForward();
789 if (aReflowStatus.IsComplete()) {
790 aReflowStatus.SetOverflowIncomplete();
795 private:
797 * @see class AutoFinish
799 void BeginFinish(nsIFrame* aChild);
800 void EndFinish(nsIFrame* aChild);
802 void SetupOverflowContList();
803 void SetUpListWalker();
804 void StepForward();
806 /* We hold a pointer to either the next-in-flow's overflow containers list
807 or, if that doesn't exist, our frame's excess overflow containers list.
808 We need to make sure that we drop that pointer if the list becomes
809 empty and is deleted elsewhere. */
810 nsFrameList* mOverflowContList;
811 /* We hold a pointer to the most recently-reflowed child that has an
812 overflow container next-in-flow. We do this because it's a known
813 good point; this pointer won't be deleted on us. We can use it to
814 recover our place in the list. */
815 nsIFrame* mPrevOverflowCont;
816 /* This is a pointer to the next overflow container's prev-in-flow, which
817 is (or should be) a child of our frame. When we hit this, we will need
818 to increment this walker to the next overflow container. */
819 nsIFrame* mSentry;
820 /* Parent of all frames in mOverflowContList. If our mOverflowContList
821 is an excessOverflowContainersProperty, or null, then this is our frame
822 (the frame that was passed in to our constructor). Otherwise this is
823 that frame's next-in-flow, and our mOverflowContList is mParent's
824 overflowContainersProperty */
825 nsContainerFrame* mParent;
826 /* Tells SetUpListWalker whether or not to walk us past any continuations
827 of overflow containers. aWalkOOFFrames is ignored when this is false. */
828 bool mSkipOverflowContainerChildren;
829 /* Tells us whether to pay attention to OOF frames or non-OOF frames */
830 bool mWalkOOFFrames;
833 inline nsFrameList* nsContainerFrame::GetOverflowFrames() const {
834 nsFrameList* list = GetProperty(OverflowProperty());
835 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
836 return list;
839 inline nsFrameList* nsContainerFrame::StealOverflowFrames() {
840 nsFrameList* list = RemoveProperty(OverflowProperty());
841 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
842 return list;
845 inline void nsContainerFrame::DestroyOverflowList() {
846 nsFrameList* list = RemovePropTableFrames(OverflowProperty());
847 MOZ_ASSERT(list && list->IsEmpty());
848 list->Delete(PresShell());
851 #endif /* nsContainerFrame_h___ */