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 
serialize(Archive & ar,std::uint32_t const)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 } // namespace mozilla
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 // 10 million pixels, converted to app units. Note that this a bit larger
38 // than 1/4 of nscoord_MAX. So, if any content gets to be this large, we're
39 // definitely in danger of grazing up against nscoord_MAX; hence, it's CRAZY.
40 #define CRAZY_COORD (10000000*60)
41 #define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
42 #endif
43 
44 /**
45  * Implementation of a container frame.
46  */
47 class nsContainerFrame : public nsSplittableFrame
48 {
49 public:
50   NS_DECL_ABSTRACT_FRAME(nsContainerFrame)
51   NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
52   NS_DECL_QUERYFRAME
53 
54   // nsIFrame overrides
55   virtual void Init(nsIContent*       aContent,
56                     nsContainerFrame* aParent,
57                     nsIFrame*         aPrevInFlow) override;
58   virtual nsContainerFrame* GetContentInsertionFrame() override
59   {
60     return this;
61   }
62 
63   virtual const nsFrameList& GetChildList(ChildListID aList) const override;
64   virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
65   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
66   virtual void ChildIsDirty(nsIFrame* aChild) override;
67 
68   virtual bool IsLeaf() const override;
69   virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
70   virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
71                                      bool aRespectClusters = true) override;
72 
73   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
74                                     nsIAtom*        aAttribute,
75                                     int32_t         aModType) override;
76 
77 #ifdef DEBUG_FRAME_DUMP
78   void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const override;
79 #endif
80 
81   // nsContainerFrame methods
82 
83   /**
84    * Called to set the initial list of frames. This happens after the frame
85    * has been initialized.
86    *
87    * This is only called once for a given child list, and won't be called
88    * at all for child lists with no initial list of frames.
89    *
90    * @param   aListID the child list identifier.
91    * @param   aChildList list of child frames. Each of the frames has its
92    *            NS_FRAME_IS_DIRTY bit set.  Must not be empty.
93    *            This method cannot handle the child list returned by
94    *            GetAbsoluteListID().
95    * @see     #Init()
96    */
97   virtual void SetInitialChildList(ChildListID aListID,
98                                    nsFrameList& aChildList);
99 
100   /**
101    * This method is responsible for appending frames to the frame
102    * list.  The implementation should append the frames to the specified
103    * child list and then generate a reflow command.
104    *
105    * @param   aListID the child list identifier.
106    * @param   aFrameList list of child frames to append. Each of the frames has
107    *            its NS_FRAME_IS_DIRTY bit set.  Must not be empty.
108    */
109   virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList);
110 
111   /**
112    * This method is responsible for inserting frames into the frame
113    * list.  The implementation should insert the new frames into the specified
114    * child list and then generate a reflow command.
115    *
116    * @param   aListID the child list identifier.
117    * @param   aPrevFrame the frame to insert frames <b>after</b>
118    * @param   aFrameList list of child frames to insert <b>after</b> aPrevFrame.
119    *            Each of the frames has its NS_FRAME_IS_DIRTY bit set
120    */
121   virtual void InsertFrames(ChildListID  aListID,
122                             nsIFrame*    aPrevFrame,
123                             nsFrameList& aFrameList);
124 
125   /**
126    * This method is responsible for removing a frame in the frame
127    * list.  The implementation should do something with the removed frame
128    * and then generate a reflow command. The implementation is responsible
129    * for destroying aOldFrame (the caller mustn't destroy aOldFrame).
130    *
131    * @param   aListID the child list identifier.
132    * @param   aOldFrame the frame to remove
133    */
134   virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
135 
136   /**
137    * Helper method to create next-in-flows if necessary. If aFrame
138    * already has a next-in-flow then this method does
139    * nothing. Otherwise, a new continuation frame is created and
140    * linked into the flow. In addition, the new frame is inserted
141    * into the principal child list after aFrame.
142    * @note calling this method on a block frame is illegal. Use
143    * nsBlockFrame::CreateContinuationFor() instead.
144    * @return the next-in-flow <b>if and only if</b> one is created. If
145    *         a next-in-flow already exists, nullptr will be returned.
146    */
147   nsIFrame* CreateNextInFlow(nsIFrame* aFrame);
148 
149   /**
150    * Delete aNextInFlow and its next-in-flows.
151    * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
152    * content was complete before aNextInFlow, so aNextInFlow and its
153    * next-in-flows no longer map any real content.
154    */
155   virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow,
156                                      bool      aDeletingEmptyFrames);
157 
158   /**
159    * Helper method to wrap views around frames. Used by containers
160    * under special circumstances (can be used by leaf frames as well)
161    */
162   static void CreateViewForFrame(nsIFrame* aFrame,
163                                  bool aForce);
164 
165   // Positions the frame's view based on the frame's origin
166   static void PositionFrameView(nsIFrame* aKidFrame);
167 
168   static nsresult ReparentFrameView(nsIFrame* aChildFrame,
169                                     nsIFrame* aOldParentFrame,
170                                     nsIFrame* aNewParentFrame);
171 
172   static nsresult ReparentFrameViewList(const nsFrameList& aChildFrameList,
173                                         nsIFrame*          aOldParentFrame,
174                                         nsIFrame*          aNewParentFrame);
175 
176   // Set the view's size and position after its frame has been reflowed.
177   //
178   // Flags:
179   // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
180   //    don't want to automatically sync the frame and view
181   // NS_FRAME_NO_SIZE_VIEW - don't size the view
182   static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
183                                        nsIFrame*       aFrame,
184                                        nsView*        aView,
185                                        const nsRect&   aVisualOverflowArea,
186                                        uint32_t        aFlags = 0);
187 
188   // Syncs properties to the top level view and window, like transparency and
189   // shadow.
190   // The SET_ASYNC indicates that the actual nsIWidget calls to sync the window
191   // properties should be done async.
192   enum {
193     SET_ASYNC = 0x01,
194   };
195   static void SyncWindowProperties(nsPresContext*       aPresContext,
196                                    nsIFrame*            aFrame,
197                                    nsView*              aView,
198                                    nsRenderingContext*  aRC,
199                                    uint32_t             aFlags);
200 
201   // Sets the view's attributes from the frame style.
202   // - visibility
203   // - clip
204   // Call this when one of these styles changes or when the view has just
205   // been created.
206   // @param aStyleContext can be null, in which case the frame's style context is used
207   static void SyncFrameViewProperties(nsPresContext*  aPresContext,
208                                       nsIFrame*        aFrame,
209                                       nsStyleContext*  aStyleContext,
210                                       nsView*         aView,
211                                       uint32_t         aFlags = 0);
212 
213   /**
214    * Converts the minimum and maximum sizes given in inner window app units to
215    * outer window device pixel sizes and assigns these constraints to the widget.
216    *
217    * @param aPresContext pres context
218    * @param aWidget widget for this frame
219    * @param minimum size of the window in app units
220    * @param maxmimum size of the window in app units
221    */
222   static void SetSizeConstraints(nsPresContext* aPresContext,
223                                  nsIWidget* aWidget,
224                                  const nsSize& aMinSize,
225                                  const nsSize& aMaxSize);
226 
227   // Used by both nsInlineFrame and nsFirstLetterFrame.
228   void DoInlineIntrinsicISize(nsRenderingContext *aRenderingContext,
229                               InlineIntrinsicISizeData *aData,
230                               nsLayoutUtils::IntrinsicISizeType aType);
231 
232   /**
233    * This is the CSS block concept of computing 'auto' widths, which most
234    * classes derived from nsContainerFrame want.
235    */
236   virtual mozilla::LogicalSize
237   ComputeAutoSize(nsRenderingContext*         aRenderingContext,
238                   mozilla::WritingMode        aWM,
239                   const mozilla::LogicalSize& aCBSize,
240                   nscoord                     aAvailableISize,
241                   const mozilla::LogicalSize& aMargin,
242                   const mozilla::LogicalSize& aBorder,
243                   const mozilla::LogicalSize& aPadding,
244                   ComputeSizeFlags            aFlags) override;
245 
246   /**
247    * Positions aChildFrame and its view (if requested), and then calls Reflow().
248    * If the reflow status after reflowing the child is FULLY_COMPLETE then any
249    * next-in-flows are deleted using DeleteNextInFlowChild().
250    *
251    * @param aContainerSize  size of the border-box of the containing frame
252    *
253    * Flags:
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_MOVE_FRAME - don't move the frame. aPos is ignored in this
257    *    case. Also implies NS_FRAME_NO_MOVE_VIEW
258    */
259   void ReflowChild(nsIFrame*                      aChildFrame,
260                    nsPresContext*                 aPresContext,
261                    ReflowOutput&           aDesiredSize,
262                    const ReflowInput&       aReflowInput,
263                    const mozilla::WritingMode&    aWM,
264                    const mozilla::LogicalPoint&   aPos,
265                    const nsSize&                  aContainerSize,
266                    uint32_t                       aFlags,
267                    nsReflowStatus&                aStatus,
268                    nsOverflowContinuationTracker* aTracker = nullptr);
269 
270   /**
271    * The second half of frame reflow. Does the following:
272    * - sets the frame's bounds
273    * - sizes and positions (if requested) the frame's view. If the frame's final
274    *   position differs from the current position and the frame itself does not
275    *   have a view, then any child frames with views are positioned so they stay
276    *   in sync
277    * - sets the view's visibility, opacity, content transparency, and clip
278    * - invoked the DidReflow() function
279    *
280    * @param aContainerSize  size of the border-box of the containing frame
281    *
282    * Flags:
283    * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aPos is ignored in this
284    *    case. Also implies NS_FRAME_NO_MOVE_VIEW
285    * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
286    *    don't want to automatically sync the frame and view
287    * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
288    */
289   static void FinishReflowChild(nsIFrame*                    aKidFrame,
290                                 nsPresContext*               aPresContext,
291                                 const ReflowOutput&   aDesiredSize,
292                                 const ReflowInput*     aReflowInput,
293                                 const mozilla::WritingMode&  aWM,
294                                 const mozilla::LogicalPoint& aPos,
295                                 const nsSize&                aContainerSize,
296                                 uint32_t                     aFlags);
297 
298   //XXX temporary: hold on to a copy of the old physical versions of
299   //    ReflowChild and FinishReflowChild so that we can convert callers
300   //    incrementally.
301   void ReflowChild(nsIFrame*                      aKidFrame,
302                    nsPresContext*                 aPresContext,
303                    ReflowOutput&           aDesiredSize,
304                    const ReflowInput&       aReflowInput,
305                    nscoord                        aX,
306                    nscoord                        aY,
307                    uint32_t                       aFlags,
308                    nsReflowStatus&                aStatus,
309                    nsOverflowContinuationTracker* aTracker = nullptr);
310 
311   static void FinishReflowChild(nsIFrame*                  aKidFrame,
312                                 nsPresContext*             aPresContext,
313                                 const ReflowOutput& aDesiredSize,
314                                 const ReflowInput*   aReflowInput,
315                                 nscoord                    aX,
316                                 nscoord                    aY,
317                                 uint32_t                   aFlags);
318 
319   static void PositionChildViews(nsIFrame* aFrame);
320 
321   // ==========================================================================
322   /* Overflow containers are continuation frames that hold overflow. They
323    * are created when the frame runs out of computed height, but still has
324    * too much content to fit in the availableHeight. The parent creates a
325    * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
326    * and adds it to its next-in-flow's overflow container list, either by
327    * adding it directly or by putting it in its own excess overflow containers
328    * list (to be drained by the next-in-flow when it calls
329    * ReflowOverflowContainerChildren). The parent continues reflow as if
330    * the frame was complete once it ran out of computed height, but returns
331    * either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
332    * status to request a next-in-flow. The parent's next-in-flow is then
333    * responsible for calling ReflowOverflowContainerChildren to (drain and)
334    * reflow these overflow continuations. Overflow containers do not affect
335    * other frames' size or position during reflow (but do affect their
336    * parent's overflow area).
337    *
338    * Overflow container continuations are different from normal continuations
339    * in that
340    *   - more than one child of the frame can have its next-in-flow broken
341    *     off and pushed into the frame's next-in-flow
342    *   - new continuations may need to be spliced into the middle of the list
343    *     or deleted continuations slipped out
344    *     e.g. A, B, C are all fixed-size containers on one page, all have
345    *      overflow beyond availableHeight, and content is dynamically added
346    *      and removed from B
347    * As a result, it is not possible to simply prepend the new continuations
348    * to the old list as with the overflowProperty mechanism. To avoid
349    * complicated list splicing, the code assumes only one overflow containers
350    * list exists for a given frame: either its own overflowContainersProperty
351    * or its prev-in-flow's excessOverflowContainersProperty, not both.
352    *
353    * The nsOverflowContinuationTracker helper class should be used for tracking
354    * overflow containers and adding them to the appropriate list.
355    * See nsBlockFrame::Reflow for a sample implementation.
356    */
357 
358   friend class nsOverflowContinuationTracker;
359 
360   typedef void (*ChildFrameMerger)(nsFrameList& aDest, nsFrameList& aSrc,
361                                    nsContainerFrame* aParent);
362   static inline void DefaultChildFrameMerge(nsFrameList& aDest,
363                                             nsFrameList& aSrc,
364                                             nsContainerFrame* aParent)
365   {
366     aDest.AppendFrames(nullptr, aSrc);
367   }
368 
369   /**
370    * Reflow overflow container children. They are invisible to normal reflow
371    * (i.e. don't affect sizing or placement of other children) and inherit
372    * width and horizontal position from their prev-in-flow.
373    *
374    * This method
375    *   1. Pulls excess overflow containers from the prev-in-flow and adds
376    *      them to our overflow container list
377    *   2. Reflows all our overflow container kids
378    *   3. Expands aOverflowRect as necessary to accomodate these children.
379    *   4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
380    *      NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
381    *      are incomplete and
382    *   5. Prepends a list of their continuations to our excess overflow
383    *      container list, to be drained into our next-in-flow when it is
384    *      reflowed.
385    *
386    * The caller is responsible for tracking any new overflow container
387    * continuations it makes, removing them from its child list, and
388    * making sure they are stored properly in the overflow container lists.
389    * The nsOverflowContinuationTracker helper class should be used for this.
390    *
391    * @param aFlags is passed through to ReflowChild
392    * @param aMergeFunc is passed to DrainExcessOverflowContainersList
393    */
394   void ReflowOverflowContainerChildren(nsPresContext*           aPresContext,
395                                        const ReflowInput& aReflowInput,
396                                        nsOverflowAreas&         aOverflowRects,
397                                        uint32_t                 aFlags,
398                                        nsReflowStatus&          aStatus,
399                                        ChildFrameMerger aMergeFunc =
400                                          DefaultChildFrameMerge);
401 
402   /**
403    * Move any frames on our overflow list to the end of our principal list.
404    * @return true if there were any overflow frames
405    */
406   virtual bool DrainSelfOverflowList() override;
407 
408 
409   /**
410    * Move all frames on our prev-in-flow's and our own ExcessOverflowContainers
411    * lists to our OverflowContainers list.  If there are frames on multiple
412    * lists they are merged using aMergeFunc.
413    * @return a pointer to our OverflowContainers list, if any
414    */
415   nsFrameList* DrainExcessOverflowContainersList(ChildFrameMerger aMergeFunc =
416                                                    DefaultChildFrameMerge);
417 
418   /**
419    * Removes aChild without destroying it and without requesting reflow.
420    * Continuations are not affected.  Checks the principal and overflow lists,
421    * and also the [excess] overflow containers lists if the frame bit
422    * NS_FRAME_IS_OVERFLOW_CONTAINER is set.  It does not check any other lists.
423    * Returns NS_ERROR_UNEXPECTED if aChild wasn't found on any of the lists
424    * mentioned above.
425    */
426   virtual nsresult StealFrame(nsIFrame* aChild);
427 
428   /**
429    * Removes the next-siblings of aChild without destroying them and without
430    * requesting reflow. Checks the principal and overflow lists (not
431    * overflow containers / excess overflow containers). Does not check any
432    * other auxiliary lists.
433    * @param aChild a child frame or nullptr
434    * @return If aChild is non-null, the next-siblings of aChild, if any.
435    *         If aChild is null, all child frames on the principal list, if any.
436    */
437   nsFrameList StealFramesAfter(nsIFrame* aChild);
438 
439   /**
440    * Add overflow containers to the display list
441    */
442   void DisplayOverflowContainers(nsDisplayListBuilder*   aBuilder,
443                                  const nsRect&           aDirtyRect,
444                                  const nsDisplayListSet& aLists);
445 
446   /**
447    * Builds display lists for the children. The background
448    * of each child is placed in the Content() list (suitable for inline
449    * children and other elements that behave like inlines,
450    * but not for in-flow block children of blocks).  DOES NOT
451    * paint the background/borders/outline of this frame. This should
452    * probably be avoided and eventually removed. It's currently here
453    * to emulate what nsContainerFrame::Paint did.
454    */
455   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
456                                 const nsRect&           aDirtyRect,
457                                 const nsDisplayListSet& aLists) override;
458 
459   static void PlaceFrameView(nsIFrame* aFrame)
460   {
461     if (aFrame->HasView())
462       nsContainerFrame::PositionFrameView(aFrame);
463     else
464       nsContainerFrame::PositionChildViews(aFrame);
465   }
466 
467   static bool FrameStartsCounterScope(nsIFrame* aFrame);
468 
469   /**
470    * Renumber the list of the counter scope started by this frame, if any.
471    * If this returns true, the frame it's called on should get the
472    * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
473    * if it's already in reflow, or via calling FrameNeedsReflow() to schedule
474    * a reflow.
475    */
476   bool RenumberList();
477 
478   /**
479    * Renumber this frame if it's a list-item, then call RenumberChildFrames.
480    * @param aOrdinal Ordinal number to start counting at.
481    *        Modifies this number for each associated list
482    *        item. Changes in the numbering due to setting
483    *        the |value| attribute are included if |aForCounting|
484    *        is false. This value is both an input and output
485    *        of this function, with the output value being the
486    *        next ordinal number to be used.
487    * @param aDepth Current depth in frame tree from root list element.
488    * @param aIncrement Amount to increase by after visiting each associated
489    *        list item, unless overridden by |value|.
490    * @param aForCounting Whether we are counting the elements or actually
491    *        restyling them. When true, this simply visits all children,
492    *        ignoring |<li value="..">| changes, effectively counting them
493    *        and storing the result in |aOrdinal|. This is useful for
494    *        |<ol reversed>|, where we need to count the number of
495    *        applicable child list elements before numbering. When false,
496    *        this will restyle all applicable descendants, and the next
497    *        ordinal value will be stored in |aOrdinal|, taking into account
498    *        any changes from |<li value="..">|.
499    */
500   bool RenumberFrameAndDescendants(int32_t* aOrdinal,
501                                    int32_t aDepth,
502                                    int32_t aIncrement,
503                                    bool aForCounting) override;
504   /**
505    * Renumber the child frames using RenumberFrameAndDescendants.
506    * See RenumberFrameAndDescendants for description of parameters.
507    */
508   virtual bool RenumberChildFrames(int32_t* aOrdinal,
509                                    int32_t aDepth,
510                                    int32_t aIncrement,
511                                    bool aForCounting);
512 
513   /**
514    * Returns a CSS Box Alignment constant which the caller can use to align
515    * the absolutely-positioned child (whose ReflowInput is aChildRI) within
516    * a CSS Box Alignment area associated with this container.
517    *
518    * The lower 8 bits of the returned value are guaranteed to form a valid
519    * argument for CSSAlignUtils::AlignJustifySelf(). (The upper 8 bits may
520    * encode an <overflow-position>.)
521    *
522    * NOTE: This default nsContainerFrame implementation is a stub, and isn't
523    * meant to be called.  Subclasses must provide their own implementations, if
524    * they use CSS Box Alignment to determine the static position of their
525    * absolutely-positioned children. (Though: if subclasses share enough code,
526    * maybe this nsContainerFrame impl should include some shared code.)
527    *
528    * @param aChildRI A ReflowInput for the positioned child frame that's being
529    *                 aligned.
530    * @param aLogicalAxis The axis (of this container frame) in which the caller
531    *                     would like to align the child frame.
532    */
533   virtual uint16_t CSSAlignmentForAbsPosChild(
534                      const ReflowInput& aChildRI,
535                      mozilla::LogicalAxis aLogicalAxis) const;
536 
537 #define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
538   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, nsFrameList)
539 
540   typedef PropertyDescriptor<nsFrameList> FrameListPropertyDescriptor;
541 
542   NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
543   NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
544   NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
545   NS_DECLARE_FRAME_PROPERTY_FRAMELIST(BackdropProperty)
546 
547 #ifdef DEBUG
548   // Use this to suppress the CRAZY_SIZE assertions.
549   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool)
550   bool IsCrazySizeAssertSuppressed() const {
551     return Properties().Get(DebugReflowingWithInfiniteISize());
552   }
553 #endif
554 
555 protected:
556   explicit nsContainerFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
557   ~nsContainerFrame();
558 
559   /**
560    * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
561    * destroying frames on lists that can contain placeholders.
562    * Derived classes must do that too, if they destroy such frame lists.
563    * See nsBlockFrame::DestroyFrom for an example.
564    */
565   void DestroyAbsoluteFrames(nsIFrame* aDestructRoot);
566 
567   /**
568    * Helper for StealFrame.  Returns true if aChild was removed from its list.
569    */
570   bool MaybeStealOverflowContainerFrame(nsIFrame* aChild);
571 
572   /**
573    * Builds a display list for non-block children that behave like
574    * inlines. This puts the background of each child into the
575    * Content() list (suitable for inline children but not for
576    * in-flow block children of blocks).
577    * @param aForcePseudoStack forces each child into a pseudo-stacking-context
578    * so its background and all other display items (except for positioned
579    * display items) go into the Content() list.
580    */
581   void BuildDisplayListForNonBlockChildren(nsDisplayListBuilder*   aBuilder,
582                                            const nsRect&           aDirtyRect,
583                                            const nsDisplayListSet& aLists,
584                                            uint32_t                aFlags = 0);
585 
586   /**
587    * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
588    * Intended as a convenience for derived classes.
589    */
590   void BuildDisplayListForInline(nsDisplayListBuilder*   aBuilder,
591                                  const nsRect&           aDirtyRect,
592                                  const nsDisplayListSet& aLists) {
593     DisplayBorderBackgroundOutline(aBuilder, aLists);
594     BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
595                                         DISPLAY_CHILD_INLINE);
596   }
597 
598 
599   // ==========================================================================
600   /* Overflow Frames are frames that did not fit and must be pulled by
601    * our next-in-flow during its reflow. (The same concept for overflow
602    * containers is called "excess frames". We should probably make the
603    * names match.)
604    */
605 
606   /**
607    * Get the frames on the overflow list.  Can return null if there are no
608    * overflow frames.  The caller does NOT take ownership of the list; it's
609    * still owned by this frame.  A non-null return value indicates that the
610    * list is nonempty.
611    */
612   inline nsFrameList* GetOverflowFrames() const;
613 
614   /**
615    * As GetOverflowFrames, but removes the overflow frames property.  The
616    * caller is responsible for deleting nsFrameList and either passing
617    * ownership of the frames to someone else or destroying the frames.
618    * A non-null return value indicates that the list is nonempty.  The
619    * recommended way to use this function it to assign its return value
620    * into an AutoFrameListPtr.
621    */
622   inline nsFrameList* StealOverflowFrames();
623 
624   /**
625    * Set the overflow list.  aOverflowFrames must not be an empty list.
626    */
627   void SetOverflowFrames(const nsFrameList& aOverflowFrames);
628 
629   /**
630    * Destroy the overflow list, which must be empty.
631    */
632   inline void DestroyOverflowList();
633 
634   /**
635    * Moves any frames on both the prev-in-flow's overflow list and the
636    * receiver's overflow to the receiver's child list.
637    *
638    * Resets the overlist pointers to nullptr, and updates the receiver's child
639    * count and content mapping.
640    *
641    * @return true if any frames were moved and false otherwise
642    */
643   bool MoveOverflowToChildList();
644 
645   /**
646    * Push aFromChild and its next siblings to the next-in-flow. Change
647    * the geometric parent of each frame that's pushed. If there is no
648    * next-in-flow the frames are placed on the overflow list (and the
649    * geometric parent is left unchanged).
650    *
651    * Updates the next-in-flow's child count. Does <b>not</b> update the
652    * pusher's child count.
653    *
654    * @param   aFromChild the first child frame to push. It is disconnected from
655    *            aPrevSibling
656    * @param   aPrevSibling aFromChild's previous sibling. Must not be null.
657    *            It's an error to push a parent's first child frame
658    */
659   void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
660 
661   // ==========================================================================
662   /*
663    * Convenience methods for traversing continuations
664    */
665 
666   struct ContinuationTraversingState
667   {
668     nsContainerFrame* mNextInFlow;
669     explicit ContinuationTraversingState(nsContainerFrame* aFrame)
670       : mNextInFlow(static_cast<nsContainerFrame*>(aFrame->GetNextInFlow()))
671     { }
672   };
673 
674   /**
675    * Find the first frame that is a child of this frame's next-in-flows,
676    * considering both their principal child lists and overflow lists.
677    */
678   nsIFrame* GetNextInFlowChild(ContinuationTraversingState& aState,
679                                bool* aIsInOverflow = nullptr);
680 
681   /**
682    * Remove the result of GetNextInFlowChild from its current parent and
683    * append it to this frame's principal child list.
684    */
685   nsIFrame* PullNextInFlowChild(ContinuationTraversingState& aState);
686 
687   // ==========================================================================
688   /*
689    * Convenience methods for nsFrameLists stored in the
690    * PresContext's proptable
691    */
692 
693   /**
694    * Get the PresContext-stored nsFrameList named aPropID for this frame.
695    * May return null.
696    */
697   nsFrameList* GetPropTableFrames(FrameListPropertyDescriptor aProperty) const;
698 
699   /**
700    * Remove and return the PresContext-stored nsFrameList named aPropID for
701    * this frame. May return null.
702    */
703   nsFrameList* RemovePropTableFrames(FrameListPropertyDescriptor aProperty);
704 
705   /**
706    * Set the PresContext-stored nsFrameList named aPropID for this frame
707    * to the given aFrameList, which must not be null.
708    */
709   void SetPropTableFrames(nsFrameList* aFrameList,
710                           FrameListPropertyDescriptor aProperty);
711 
712   /**
713    * Safely destroy the frames on the nsFrameList stored on aProp for this
714    * frame then remove the property and delete the frame list.
715    * Nothing happens if the property doesn't exist.
716    */
717   void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
718                                   nsIPresShell* aPresShell,
719                                   mozilla::FramePropertyTable* aPropTable,
720                                   FrameListPropertyDescriptor aProp);
721 
722   // ==========================================================================
723 
724   // Helper used by Progress and Meter frames. Returns true if the bar should
725   // be rendered vertically, based on writing-mode and -moz-orient properties.
726   bool ResolvedOrientationIsVertical();
727 
728   // ==========================================================================
729 
730   nsFrameList mFrames;
731 };
732 
733 // ==========================================================================
734 /* The out-of-flow-related code below is for a hacky way of splitting
735  * absolutely-positioned frames. Basically what we do is split the frame
736  * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
737  * container. This isn't an ideal solution, but it lets us print the content
738  * at least. See bug 154892.
739  */
740 
741 #define IS_TRUE_OVERFLOW_CONTAINER(frame)                      \
742   (  (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)  \
743   && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&      \
744         frame->IsAbsolutelyPositioned()  )  )
745 //XXXfr This check isn't quite correct, because it doesn't handle cases
746 //      where the out-of-flow has overflow.. but that's rare.
747 //      We'll need to revisit the way abspos continuations are handled later
748 //      for various reasons, this detail is one of them. See bug 154892
749 
750 /**
751  * Helper class for tracking overflow container continuations during reflow.
752  *
753  * A frame is related to two sets of overflow containers: those that /are/
754  * its own children, and those that are /continuations/ of its children.
755  * This tracker walks through those continuations (the frame's NIF's children)
756  * and their prev-in-flows (a subset of the frame's normal and overflow
757  * container children) in parallel. It allows the reflower to synchronously
758  * walk its overflow continuations while it loops through and reflows its
759  * children. This makes it possible to insert new continuations at the correct
760  * place in the overflow containers list.
761  *
762  * The reflower is expected to loop through its children in the same order it
763  * looped through them the last time (if there was a last time).
764  * For each child, the reflower should either
765  *   - call Skip for the child if was not reflowed in this pass
766  *   - call Insert for the overflow continuation if the child was reflowed
767  *     but has incomplete overflow
768  *   - call Finished for the child if it was reflowed in this pass but
769  *     is either complete or has a normal next-in-flow. This call can
770  *     be skipped if the child did not previously have an overflow
771  *     continuation.
772  */
773 class nsOverflowContinuationTracker {
774 public:
775   /**
776    * Initializes an nsOverflowContinuationTracker to help track overflow
777    * continuations of aFrame's children. Typically invoked on 'this'.
778    *
779    * aWalkOOFFrames determines whether the walker skips out-of-flow frames
780    * or skips non-out-of-flow frames.
781    *
782    * Don't set aSkipOverflowContainerChildren to false unless you plan
783    * to walk your own overflow container children. (Usually they are handled
784    * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
785    * if aSkipOverflowContainerChildren is false.
786    */
787   nsOverflowContinuationTracker(nsContainerFrame* aFrame,
788                                 bool              aWalkOOFFrames,
789                                 bool              aSkipOverflowContainerChildren = true);
790   /**
791    * This function adds an overflow continuation to our running list and
792    * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
793    *
794    * aReflowStatus should preferably be specific to the recently-reflowed
795    * child and not influenced by any of its siblings' statuses. This
796    * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
797    * to be reflowed. (Its need for reflow depends on changes to its
798    * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
799    *
800    * The caller MUST disconnect the frame from its parent's child list
801    * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
802    * StealFrame is much more inefficient than disconnecting in place
803    * during Reflow, which the caller is able to do but we are not).
804    *
805    * The caller MUST NOT disconnect the frame from its parent's
806    * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
807    * (In this case we will disconnect and reconnect it ourselves.)
808    */
809   nsresult Insert(nsIFrame*       aOverflowCont,
810                   nsReflowStatus& aReflowStatus);
811   /**
812    * Begin/EndFinish() must be called for each child that is reflowed
813    * but no longer has an overflow continuation. (It may be called for
814    * other children, but in that case has no effect.) It increments our
815    * walker and makes sure we drop any dangling pointers to its
816    * next-in-flow. This function MUST be called before stealing or
817    * deleting aChild's next-in-flow.
818    * The AutoFinish helper object does that for you. Use it like so:
819    * if (kidNextInFlow) {
820    *   nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
821    *   ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
822    * }
823    */
824   class MOZ_RAII AutoFinish {
825   public:
826     AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
827       : mTracker(aTracker), mChild(aChild)
828     {
829       if (mTracker) mTracker->BeginFinish(mChild);
830     }
831     ~AutoFinish()
832     {
833       if (mTracker) mTracker->EndFinish(mChild);
834     }
835   private:
836     nsOverflowContinuationTracker* mTracker;
837     nsIFrame* mChild;
838   };
839 
840   /**
841    * This function should be called for each child that isn't reflowed.
842    * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
843    * reflow flag if it encounters an overflow continuation so that our
844    * next-in-flow doesn't get prematurely deleted. It MUST be called on
845    * each unreflowed child that has an overflow container continuation;
846    * it MAY be called on other children, but it isn't necessary (doesn't
847    * do anything).
848    */
849   void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
850   {
851     NS_PRECONDITION(aChild, "null ptr");
852     if (aChild == mSentry) {
853       StepForward();
854       NS_MergeReflowStatusInto(&aReflowStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
855     }
856   }
857 
858 private:
859 
860   /**
861    * @see class AutoFinish
862    */
863   void BeginFinish(nsIFrame* aChild);
864   void EndFinish(nsIFrame* aChild);
865 
866   void SetupOverflowContList();
867   void SetUpListWalker();
868   void StepForward();
869 
870   /* We hold a pointer to either the next-in-flow's overflow containers list
871      or, if that doesn't exist, our frame's excess overflow containers list.
872      We need to make sure that we drop that pointer if the list becomes
873      empty and is deleted elsewhere. */
874   nsFrameList* mOverflowContList;
875   /* We hold a pointer to the most recently-reflowed child that has an
876      overflow container next-in-flow. We do this because it's a known
877      good point; this pointer won't be deleted on us. We can use it to
878      recover our place in the list. */
879   nsIFrame* mPrevOverflowCont;
880   /* This is a pointer to the next overflow container's prev-in-flow, which
881      is (or should be) a child of our frame. When we hit this, we will need
882      to increment this walker to the next overflow container. */
883   nsIFrame* mSentry;
884   /* Parent of all frames in mOverflowContList. If our mOverflowContList
885      is an excessOverflowContainersProperty, or null, then this is our frame
886      (the frame that was passed in to our constructor). Otherwise this is
887      that frame's next-in-flow, and our mOverflowContList is mParent's
888      overflowContainersProperty */
889   nsContainerFrame* mParent;
890   /* Tells SetUpListWalker whether or not to walk us past any continuations
891      of overflow containers. aWalkOOFFrames is ignored when this is false. */
892   bool mSkipOverflowContainerChildren;
893   /* Tells us whether to pay attention to OOF frames or non-OOF frames */
894   bool mWalkOOFFrames;
895 };
896 
897 inline
898 nsFrameList*
899 nsContainerFrame::GetOverflowFrames() const
900 {
901   nsFrameList* list = Properties().Get(OverflowProperty());
902   NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
903   return list;
904 }
905 
906 inline
907 nsFrameList*
908 nsContainerFrame::StealOverflowFrames()
909 {
910   nsFrameList* list = Properties().Remove(OverflowProperty());
911   NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
912   return list;
913 }
914 
915 inline void
916 nsContainerFrame::DestroyOverflowList()
917 {
918   nsFrameList* list = RemovePropTableFrames(OverflowProperty());
919   MOZ_ASSERT(list && list->IsEmpty());
920   list->Delete(PresContext()->PresShell());
921 }
922 
923 #endif /* nsContainerFrame_h___ */
924