Source code

Revision control

Other Tools

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