Coverage Report

Created: 2018-09-25 14:53

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