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/. */
8 * rendering object for CSS display:block, inline-block, and list-item
9 * boxes, also used for various anonymous boxes
12 #ifndef nsBlockFrame_h___
13 #define nsBlockFrame_h___
15 #include "nsContainerFrame.h"
16 #include "nsHTMLParts.h"
17 #include "nsLineBox.h"
18 #include "nsCSSPseudoElements.h"
19 #include "nsFloatManager.h"
21 enum class LineReflowStatus
{
22 // The line was completely reflowed and fit in available width, and we should
23 // try to pull up content from the next line if possible.
25 // The line was completely reflowed and fit in available width, but we should
26 // not try to pull up content from the next line.
28 // We need to reflow the line again at its current vertical position. The
29 // new reflow should not try to pull up any frames from the next line.
31 // We need to reflow the line again using the floats from its height
32 // this reflow, since its height made it hit floats that were not
33 // adjacent to its top.
35 // We need to reflow the line again at a lower vertical postion where there
36 // may be more horizontal space due to different float configuration.
38 // The line did not fit in the available vertical space. Try pushing it to
39 // the next page or column if it's not the first line on the current
44 class nsBlockInFlowLineIterator
;
46 class BlockReflowState
;
48 class ServoRestyleState
;
50 } // namespace mozilla
54 * -- The overflow out-of-flows list contains the out-of-
55 * flow frames whose placeholders are in the overflow list.
56 * -- A given piece of content has at most one placeholder
57 * frame in a block's normal child list.
58 * -- While a block is being reflowed, and from then until
59 * its next-in-flow is reflowed it may have a
60 * PushedFloatProperty frame property that points to
61 * an nsFrameList. This list contains continuations for
62 * floats whose prev-in-flow is in the block's regular float
63 * list and first-in-flows of floats that did not fit, but
64 * whose placeholders are in the block or one of its
66 * -- In all these frame lists, if there are two frames for
67 * the same content appearing in the list, then the frames
68 * appear with the prev-in-flow before the next-in-flow.
69 * -- While reflowing a block, its overflow line list
70 * will usually be empty but in some cases will have lines
71 * (while we reflow the block at its shrink-wrap width).
72 * In this case any new overflowing content must be
73 * prepended to the overflow lines.
77 * Base class for block and inline frames.
78 * The block frame has an additional child list, FrameChildListID::Absolute,
79 * which contains the absolutely positioned frames.
81 class nsBlockFrame
: public nsContainerFrame
{
82 using BlockReflowState
= mozilla::BlockReflowState
;
85 NS_DECL_FRAMEARENA_HELPERS(nsBlockFrame
)
87 typedef nsLineList::iterator LineIterator
;
88 typedef nsLineList::const_iterator ConstLineIterator
;
89 typedef nsLineList::reverse_iterator ReverseLineIterator
;
90 typedef nsLineList::const_reverse_iterator ConstReverseLineIterator
;
92 LineIterator
LinesBegin() { return mLines
.begin(); }
93 LineIterator
LinesEnd() { return mLines
.end(); }
94 ConstLineIterator
LinesBegin() const { return mLines
.begin(); }
95 ConstLineIterator
LinesEnd() const { return mLines
.end(); }
96 ReverseLineIterator
LinesRBegin() { return mLines
.rbegin(); }
97 ReverseLineIterator
LinesREnd() { return mLines
.rend(); }
98 ConstReverseLineIterator
LinesRBegin() const { return mLines
.rbegin(); }
99 ConstReverseLineIterator
LinesREnd() const { return mLines
.rend(); }
100 LineIterator
LinesBeginFrom(nsLineBox
* aList
) { return mLines
.begin(aList
); }
101 ReverseLineIterator
LinesRBeginFrom(nsLineBox
* aList
) {
102 return mLines
.rbegin(aList
);
105 // Methods declared to be used in 'range-based-for-loop'
106 nsLineList
& Lines() { return mLines
; }
107 const nsLineList
& Lines() const { return mLines
; }
109 friend nsBlockFrame
* NS_NewBlockFrame(mozilla::PresShell
* aPresShell
,
110 ComputedStyle
* aStyle
);
116 void Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
117 nsIFrame
* aPrevInFlow
) override
;
118 void SetInitialChildList(ChildListID aListID
,
119 nsFrameList
&& aChildList
) override
;
120 void AppendFrames(ChildListID aListID
, nsFrameList
&& aFrameList
) override
;
121 void InsertFrames(ChildListID aListID
, nsIFrame
* aPrevFrame
,
122 const nsLineList::iterator
* aPrevFrameLine
,
123 nsFrameList
&& aFrameList
) override
;
124 void RemoveFrame(DestroyContext
&, ChildListID
, nsIFrame
* aOldFrame
) override
;
125 nsContainerFrame
* GetContentInsertionFrame() override
;
126 void AppendDirectlyOwnedAnonBoxes(nsTArray
<OwnedAnonBox
>& aResult
) override
;
127 const nsFrameList
& GetChildList(ChildListID aListID
) const override
;
128 void GetChildLists(nsTArray
<ChildList
>* aLists
) const override
;
129 nscoord
SynthesizeFallbackBaseline(
130 mozilla::WritingMode aWM
,
131 BaselineSharingGroup aBaselineGroup
) const override
;
132 BaselineSharingGroup
GetDefaultBaselineSharingGroup() const override
{
133 return BaselineSharingGroup::Last
;
135 Maybe
<nscoord
> GetNaturalBaselineBOffset(
136 mozilla::WritingMode aWM
, BaselineSharingGroup aBaselineGroup
,
137 BaselineExportContext aExportContext
) const override
;
138 nscoord
GetCaretBaseline() const override
;
139 void Destroy(DestroyContext
&) override
;
141 bool IsFloatContainingBlock() const override
;
142 void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
143 const nsDisplayListSet
& aLists
) override
;
145 void InvalidateFrame(uint32_t aDisplayItemKey
= 0,
146 bool aRebuildDisplayItems
= true) override
;
147 void InvalidateFrameWithRect(const nsRect
& aRect
,
148 uint32_t aDisplayItemKey
= 0,
149 bool aRebuildDisplayItems
= true) override
;
151 #ifdef DEBUG_FRAME_DUMP
152 void List(FILE* out
= stderr
, const char* aPrefix
= "",
153 ListFlags aFlags
= ListFlags()) const override
;
154 nsresult
GetFrameName(nsAString
& aResult
) const override
;
158 const char* LineReflowStatusToString(
159 LineReflowStatus aLineReflowStatus
) const;
163 mozilla::a11y::AccType
AccessibleType() override
;
166 // Line cursor methods to speed up line searching in which one query result
167 // is expected to be close to the next in general. This is mainly for
168 // searching line(s) containing a point. It is also used as a cache for local
169 // computation. The basic idea for the former is that we set the cursor
170 // property if the lines' overflowArea.InkOverflow().ys and
171 // overflowArea.InkOverflow().yMosts are non-decreasing
172 // (considering only non-empty overflowArea.InkOverflow()s; empty
173 // overflowArea.InkOverflow()s never participate in event handling
174 // or painting), and the block has sufficient number of lines. The
175 // cursor property points to a "recently used" line. If we get a
176 // series of requests that work on lines
177 // "near" the cursor, then we can find those nearby lines quickly by
178 // starting our search at the cursor.
180 // We have two independent line cursors, one used for display-list building
181 // and the other for a11y or other frame queries. Either or both may be
182 // present at any given time. When we reflow or otherwise munge the lines,
183 // both cursors will be cleared.
184 // The display cursor is only created and used if the lines satisfy the non-
185 // decreasing y-coordinate condition (see SetupLineCursorForDisplay comment
186 // below), whereas the query cursor may be created for any block. The two
187 // are separated so creating a cursor for a11y queries (eg GetRenderedText)
188 // does not risk confusing the display-list building code.
190 // Clear out line cursors because we're disturbing the lines (i.e., Reflow)
191 void ClearLineCursors() {
192 if (MaybeHasLineCursor()) {
193 ClearLineCursorForDisplay();
194 ClearLineCursorForQuery();
195 RemoveStateBits(NS_BLOCK_HAS_LINE_CURSOR
);
199 void ClearLineCursorForDisplay() {
200 RemoveProperty(LineCursorPropertyDisplay());
202 void ClearLineCursorForQuery() { RemoveProperty(LineCursorPropertyQuery()); }
204 // Clear just the line-iterator property; this is used if we need to get a
205 // LineIterator temporarily during reflow, when using a persisted iterator
206 // would be invalid. So we clear the stored property immediately after use.
207 void ClearLineIterator() { RemoveProperty(LineIteratorProperty()); }
209 // Get the first line that might contain y-coord 'y', or nullptr if you must
210 // search all lines. If nonnull is returned then we guarantee that the lines'
211 // combinedArea.ys and combinedArea.yMosts are non-decreasing.
212 // The actual line returned might not contain 'y', but if not, it is
213 // guaranteed to be before any line which does contain 'y'.
214 nsLineBox
* GetFirstLineContaining(nscoord y
);
216 // Ensure the frame has a display-list line cursor, initializing it to the
217 // first line if it is not already present. (If there's an existing cursor,
218 // it is left untouched.) Only call this if you guarantee that the lines'
219 // combinedArea.ys and combinedArea.yMosts are non-decreasing.
220 void SetupLineCursorForDisplay();
222 // Ensure the frame has a query line cursor, initializing it to the first
223 // line if it is not already present. (If there's an existing cursor, it is
225 void SetupLineCursorForQuery();
227 void ChildIsDirty(nsIFrame
* aChild
) override
;
229 bool IsEmpty() override
;
230 bool CachedIsEmpty() override
;
231 bool IsSelfEmpty() override
;
233 // Given that we have a ::marker frame, does it actually draw something, i.e.,
234 // do we have either a 'list-style-type' or 'list-style-image' that is
235 // not 'none', and no 'content'?
236 bool MarkerIsEmpty() const;
239 * Return true if this frame has a ::marker frame.
241 bool HasMarker() const { return HasOutsideMarker() || HasInsideMarker(); }
244 * @return true if this frame has an inside ::marker frame.
246 bool HasInsideMarker() const {
247 return HasAnyStateBits(NS_BLOCK_FRAME_HAS_INSIDE_MARKER
);
251 * @return true if this frame has an outside ::marker frame.
253 bool HasOutsideMarker() const {
254 return HasAnyStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER
);
258 * @return the ::marker frame or nullptr if we don't have one.
260 nsIFrame
* GetMarker() const {
261 nsIFrame
* outside
= GetOutsideMarker();
262 return outside
? outside
: GetInsideMarker();
266 * @return the first-letter frame or nullptr if we don't have one.
268 nsIFrame
* GetFirstLetter() const;
271 * @return the ::first-line frame or nullptr if we don't have one.
273 nsIFrame
* GetFirstLineFrame() const;
275 void MarkIntrinsicISizesDirty() override
;
278 // Whether CSS text-indent should be applied to the given line.
279 bool TextIndentAppliesTo(const LineIterator
& aLine
) const;
281 void CheckIntrinsicCacheAgainstShrinkWrapState();
283 template <typename LineIteratorType
>
284 Maybe
<nscoord
> GetBaselineBOffset(LineIteratorType aStart
,
285 LineIteratorType aEnd
,
286 mozilla::WritingMode aWM
,
287 BaselineSharingGroup aBaselineGroup
,
288 BaselineExportContext aExportContext
) const;
291 nscoord
GetMinISize(gfxContext
* aRenderingContext
) override
;
292 nscoord
GetPrefISize(gfxContext
* aRenderingContext
) override
;
294 nsRect
ComputeTightBounds(DrawTarget
* aDrawTarget
) const override
;
296 nsresult
GetPrefWidthTightBounds(gfxContext
* aContext
, nscoord
* aX
,
297 nscoord
* aXMost
) override
;
300 * Compute the final block size of this frame.
302 * @param aState BlockReflowState passed from parent during reflow.
303 * Note: aState.mReflowStatus is mostly an "input" parameter. When this
304 * method is called, it should represent what our status would be as if
305 * we were shrinkwrapping our children's block-size. This method will
306 * then adjust it before returning if our status is different in light
307 * of our actual final block-size and current page/column's available
309 * @param aBEndEdgeOfChildren The distance between this frame's block-start
310 * border-edge and the block-end edge of our last child's border-box.
311 * This is effectively our block-start border-padding plus the
312 * block-size of our children, precomputed outside of this function.
313 * @return our final block-size with respect to aReflowInput's writing-mode.
315 nscoord
ComputeFinalBSize(BlockReflowState
& aState
,
316 nscoord aBEndEdgeOfChildren
);
318 void Reflow(nsPresContext
* aPresContext
, ReflowOutput
& aDesiredSize
,
319 const ReflowInput
& aReflowInput
,
320 nsReflowStatus
& aStatus
) override
;
323 * Move any frames on our overflow list to the end of our principal list.
324 * @return true if there were any overflow frames
326 bool DrainSelfOverflowList() override
;
328 void StealFrame(nsIFrame
* aChild
) override
;
330 void DeleteNextInFlowChild(DestroyContext
&, nsIFrame
* aNextInFlow
,
331 bool aDeletingEmptyFrames
) override
;
334 * This is a special method that allows a child class of nsBlockFrame to
335 * return a special, customized nsStyleText object to the nsLineLayout
336 * constructor. It is used when the nsBlockFrame child needs to specify its
337 * custom rendering style.
339 virtual const nsStyleText
* StyleTextForLineLayout();
342 * Determines whether the collapsed margin carried out of the last
343 * line includes the margin-top of a line with clearance (in which
344 * case we must avoid collapsing that margin with our bottom margin)
346 bool CheckForCollapsedBEndMarginFromClearanceLine();
348 static nsresult
GetCurrentLine(BlockReflowState
* aState
,
349 nsLineBox
** aOutCurrentLine
);
352 * Determine if this block is a margin root at the top/bottom edges.
354 void IsMarginRoot(bool* aBStartMarginRoot
, bool* aBEndMarginRoot
);
356 static bool BlockNeedsFloatManager(nsIFrame
* aBlock
);
359 * Returns whether aFrame is a block frame that will wrap its contents
360 * around floats intruding on it from the outside. (aFrame need not
361 * be a block frame, but if it's not, the result will be false.)
363 * Note: We often use the term "float-avoiding block" to refer to
364 * block-level frames for whom this function returns false.
366 static bool BlockCanIntersectFloats(nsIFrame
* aFrame
);
369 * Returns the inline size that needs to be cleared past floats for
370 * blocks that avoid (i.e. cannot intersect) floats. aState must already
371 * have GetFloatAvailableSpace called on it for the block-dir position that
372 * we care about (which need not be its current mBCoord)
374 struct FloatAvoidingISizeToClear
{
375 // Note that we care about the inline-start margin but can ignore
376 // the inline-end margin.
377 nscoord marginIStart
, borderBoxISize
;
379 static FloatAvoidingISizeToClear
ISizeToClearPastFloats(
380 const BlockReflowState
& aState
,
381 const mozilla::LogicalRect
& aFloatAvailableSpace
,
382 nsIFrame
* aFloatAvoidingBlock
);
385 * Creates a contination for aFloat and adds it to the list of overflow
386 * floats. Also updates aState.mReflowStatus to include the float's
387 * incompleteness. Must only be called while this block frame is in reflow.
388 * aFloatStatus must be the float's true, unmodified reflow status.
390 void SplitFloat(BlockReflowState
& aState
, nsIFrame
* aFloat
,
391 const nsReflowStatus
& aFloatStatus
);
394 * Walks up the frame tree, starting with aCandidate, and returns the first
395 * block frame that it encounters.
397 static nsBlockFrame
* GetNearestAncestorBlock(nsIFrame
* aCandidate
);
405 * Update the styles of our various pseudo-elements (marker, first-line,
406 * etc, but _not_ first-letter).
408 void UpdatePseudoElementStyles(mozilla::ServoRestyleState
& aRestyleState
);
410 // Update our first-letter styles during stylo post-traversal. This needs to
411 // be done at a slightly different time than our other pseudo-elements.
412 void UpdateFirstLetterStyle(mozilla::ServoRestyleState
& aRestyleState
);
415 explicit nsBlockFrame(ComputedStyle
* aStyle
, nsPresContext
* aPresContext
,
416 ClassID aID
= kClassID
)
417 : nsContainerFrame(aStyle
, aPresContext
, aID
) {
423 virtual ~nsBlockFrame();
425 void DidSetComputedStyle(ComputedStyle
* aOldStyle
) override
;
428 already_AddRefed
<ComputedStyle
> GetFirstLetterStyle(
429 nsPresContext
* aPresContext
);
432 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorPropertyDisplay
, nsLineBox
)
433 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorPropertyQuery
, nsLineBox
)
434 // Note that the NS_BLOCK_HAS_LINE_CURSOR flag does not necessarily mean the
435 // cursor is present, as it covers both the "display" and "query" cursors,
436 // but may remain set if they have been separately deleted. In such a case,
437 // the Get* accessors will be slightly more expensive, but will still safely
438 // return null if the cursor is absent.
439 bool MaybeHasLineCursor() {
440 return HasAnyStateBits(NS_BLOCK_HAS_LINE_CURSOR
);
442 nsLineBox
* GetLineCursorForDisplay() {
443 return MaybeHasLineCursor() ? GetProperty(LineCursorPropertyDisplay())
446 nsLineBox
* GetLineCursorForQuery() {
447 return MaybeHasLineCursor() ? GetProperty(LineCursorPropertyQuery())
451 nsLineBox
* NewLineBox(nsIFrame
* aFrame
, bool aIsBlock
) {
452 return NS_NewLineBox(PresShell(), aFrame
, aIsBlock
);
454 nsLineBox
* NewLineBox(nsLineBox
* aFromLine
, nsIFrame
* aFrame
,
456 return NS_NewLineBox(PresShell(), aFromLine
, aFrame
, aCount
);
458 void FreeLineBox(nsLineBox
* aLine
) {
459 if (aLine
== GetLineCursorForDisplay()) {
460 ClearLineCursorForDisplay();
462 if (aLine
== GetLineCursorForQuery()) {
463 ClearLineCursorForQuery();
465 aLine
->Destroy(PresShell());
468 * Helper method for StealFrame.
470 void RemoveFrameFromLine(nsIFrame
* aChild
, nsLineList::iterator aLine
,
471 nsFrameList
& aFrameList
, nsLineList
& aLineList
);
473 void TryAllLines(nsLineList::iterator
* aIterator
,
474 nsLineList::iterator
* aStartIterator
,
475 nsLineList::iterator
* aEndIterator
, bool* aInOverflowLines
,
476 FrameLines
** aOverflowLines
);
478 /** move the frames contained by aLine by aDeltaBCoord
479 * if aLine is a block, its child floats are added to the state manager
481 void SlideLine(BlockReflowState
& aState
, nsLineBox
* aLine
,
482 nscoord aDeltaBCoord
);
484 void UpdateLineContainerSize(nsLineBox
* aLine
,
485 const nsSize
& aNewContainerSize
);
487 // helper for SlideLine and UpdateLineContainerSize
488 void MoveChildFramesOfLine(nsLineBox
* aLine
, nscoord aDeltaBCoord
);
490 // Returns block-end edge of children.
491 nscoord
ComputeFinalSize(const ReflowInput
& aReflowInput
,
492 BlockReflowState
& aState
, ReflowOutput
& aMetrics
);
495 * Calculates the necessary shift to honor 'align-content' and applies it.
497 void AlignContent(BlockReflowState
& aState
, ReflowOutput
& aMetrics
,
498 nscoord aBEndEdgeOfChildren
);
499 // Stash the effective align-content shift value between reflows
500 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(AlignContentShift
, nscoord
)
503 * Helper method for Reflow(). Computes the overflow areas created by our
504 * children, and includes them into aOverflowAreas.
506 void ComputeOverflowAreas(mozilla::OverflowAreas
& aOverflowAreas
,
507 nscoord aBEndEdgeOfChildren
,
508 const nsStyleDisplay
* aDisplay
) const;
511 * Helper method for ComputeOverflowAreas(). Incorporates aBEndEdgeOfChildren
512 * into the aOverflowAreas.
514 void ConsiderBlockEndEdgeOfChildren(mozilla::OverflowAreas
& aOverflowAreas
,
515 nscoord aBEndEdgeOfChildren
,
516 const nsStyleDisplay
* aDisplay
) const;
519 * Add the frames in aFrameList to this block after aPrevSibling.
520 * This block thinks in terms of lines, but the frame construction code
521 * knows nothing about lines at all so we need to find the line that
522 * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
523 * New lines are created as necessary to handle block data in aFrameList.
524 * This function will clear aFrameList.
526 * aPrevSiblingLine, if present, must be the line containing aPrevSibling.
527 * Providing it will make this function faster.
529 void AddFrames(nsFrameList
&& aFrameList
, nsIFrame
* aPrevSibling
,
530 const nsLineList::iterator
* aPrevSiblingLine
);
532 // Return the :-moz-block-ruby-content child frame, if any.
533 // (It's non-null only if this block frame is for 'display:block ruby'.)
534 nsContainerFrame
* GetRubyContentPseudoFrame();
537 * Perform Bidi resolution on this frame
539 nsresult
ResolveBidi();
542 * Test whether the frame is a form control in a visual Bidi page.
543 * This is necessary for backwards-compatibility, because most visual
544 * pages use logical order for form controls so that they will
545 * display correctly on native widgets in OSs with Bidi support
546 * @param aPresContext the pres context
547 * @return whether the frame is a BIDI form control
549 bool IsVisualFormControl(nsPresContext
* aPresContext
);
551 /** Whether this block has an effective align-content property */
552 bool IsAligned() const {
553 return StylePosition()->mAlignContent
.primary
!=
554 mozilla::StyleAlignFlags::NORMAL
;
557 nscoord
GetAlignContentShift() const {
558 return IsAligned() ? GetProperty(AlignContentShift()) : 0;
562 * For text-wrap:balance, we iteratively try reflowing with adjusted inline
563 * size to find the "best" result (the tightest size that can be applied
564 * without increasing the total line count of the block).
565 * This record is used to manage the state of these "trial reflows", and
566 * return results from the final trial.
568 struct TrialReflowState
{
569 // Values pre-computed at start of Reflow(), constant across trials.
570 const nscoord mConsumedBSize
;
571 const nscoord mEffectiveContentBoxBSize
;
572 bool mNeedFloatManager
;
573 // [out] Whether reflowing resulted in use of an overflow-wrap break.
574 bool mUsedOverflowWrap
= false;
575 // Settings for the current trial.
576 bool mBalancing
= false;
578 // Results computed during the trial reflow. Values from the final trial
579 // will be used by the remainder of Reflow().
580 mozilla::OverflowAreas mOcBounds
;
581 mozilla::OverflowAreas mFcBounds
;
582 nscoord mBlockEndEdgeOfChildren
= 0;
583 nscoord mContainerWidth
= 0;
585 // Initialize for the initial trial reflow, with zero inset.
586 TrialReflowState(nscoord aConsumedBSize
, nscoord aEffectiveContentBoxBSize
,
587 bool aNeedFloatManager
)
588 : mConsumedBSize(aConsumedBSize
),
589 mEffectiveContentBoxBSize(aEffectiveContentBoxBSize
),
590 mNeedFloatManager(aNeedFloatManager
) {}
592 // Adjust the inset amount, and reset state for a new trial.
593 void ResetForBalance(nscoord aInsetDelta
) {
594 // Tells the reflow-lines loop we must consider all lines "dirty" (as we
595 // are modifying the effective inline-size to be used).
597 // Adjust inset to apply.
598 mInset
+= aInsetDelta
;
599 // Re-initialize state that the reflow loop will compute.
602 mBlockEndEdgeOfChildren
= 0;
604 mUsedOverflowWrap
= false;
609 * Internal helper for Reflow(); may be called repeatedly during a single
610 * Reflow() in order to implement text-wrap:balance.
611 * This method applies aTrialState.mInset during line-breaking to reduce
612 * the effective available inline-size (without affecting alignment).
614 nsReflowStatus
TrialReflow(nsPresContext
* aPresContext
,
615 ReflowOutput
& aMetrics
,
616 const ReflowInput
& aReflowInput
,
617 TrialReflowState
& aTrialState
);
621 * Helper function for the frame ctor to register a ::marker frame.
623 void SetMarkerFrameForListItem(nsIFrame
* aMarkerFrame
);
626 * Does all the real work for removing aDeletedFrame
627 * -- finds the line containing aDeletedFrame
628 * -- removes all aDeletedFrame next-in-flows (or all continuations,
629 * if REMOVE_FIXED_CONTINUATIONS is given)
630 * -- marks lines dirty as needed
631 * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
632 * case textruns do not need to be dirtied)
633 * -- destroys all removed frames
635 enum { REMOVE_FIXED_CONTINUATIONS
= 0x02, FRAMES_ARE_EMPTY
= 0x04 };
636 void DoRemoveFrame(DestroyContext
&, nsIFrame
* aDeletedFrame
, uint32_t aFlags
);
638 void ReparentFloats(nsIFrame
* aFirstFrame
, nsBlockFrame
* aOldParent
,
639 bool aReparentSiblings
);
641 bool ComputeCustomOverflow(mozilla::OverflowAreas
&) override
;
643 void UnionChildOverflow(mozilla::OverflowAreas
&) override
;
646 * Load all of aFrame's floats into the float manager iff aFrame is not a
647 * block formatting context. Handles all necessary float manager translations;
648 * assumes float manager is in aFrame's parent's coord system.
650 * Safe to call on non-blocks (does nothing).
652 static void RecoverFloatsFor(nsIFrame
* aFrame
, nsFloatManager
& aFloatManager
,
653 mozilla::WritingMode aWM
,
654 const nsSize
& aContainerSize
);
657 * Determine if we have any pushed floats from a previous continuation.
659 * @returns true, if any of the floats at the beginning of our mFloats list
660 * have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise.
662 bool HasPushedFloatsFromPrevContinuation() const;
664 // @see nsIFrame::AddSizeOfExcludingThisForTree
665 void AddSizeOfExcludingThisForTree(nsWindowSizes
&) const override
;
668 * Clears any -webkit-line-clamp ellipsis on a line in this block or one
669 * of its descendants.
671 void ClearLineClampEllipsis();
674 * Returns whether this block is in a -webkit-line-clamp context. That is,
675 * whether this block is in a block formatting-context whose root block has
676 * -webkit-line-clamp: <n>.
678 bool IsInLineClampContext() const;
681 * @return false iff this block does not have a float on any child list.
682 * This function is O(1).
684 bool MaybeHasFloats() const {
685 if (!mFloats
.IsEmpty()) {
688 // XXX this could be replaced with HasPushedFloats() if we enforced
689 // removing the property when the frame list becomes empty.
690 nsFrameList
* list
= GetPushedFloats();
691 if (list
&& !list
->IsEmpty()) {
694 // For the OverflowOutOfFlowsProperty I think we do enforce that, but it's
695 // a mix of out-of-flow frames, so that's why the method name has "Maybe".
696 return HasAnyStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS
);
700 /** grab overflow lines from this block's prevInFlow, and make them
701 * part of this block's mLines list.
702 * @return true if any lines were drained.
704 bool DrainOverflowLines();
707 * Moves frames from our PushedFloats list back into our mFloats list.
709 void DrainSelfPushedFloats();
712 * First calls DrainSelfPushedFloats() then grabs pushed floats from this
713 * block's prev-in-flow, and splice them into this block's mFloats list too.
715 void DrainPushedFloats();
717 /** Load all our floats into the float manager (without reflowing them).
718 * Assumes float manager is in our own coordinate system.
720 void RecoverFloats(nsFloatManager
& aFloatManager
, mozilla::WritingMode aWM
,
721 const nsSize
& aContainerSize
);
723 /** Reflow pushed floats
725 void ReflowPushedFloats(BlockReflowState
& aState
,
726 mozilla::OverflowAreas
& aOverflowAreas
);
729 * Find any trailing BR clear from the last line of this block (or from its
732 mozilla::StyleClear
FindTrailingClear();
735 * Remove a float from our float list.
737 void RemoveFloat(nsIFrame
* aFloat
);
739 * Remove a float from the float cache for the line its placeholder is on.
741 void RemoveFloatFromFloatCache(nsIFrame
* aFloat
);
743 void CollectFloats(nsIFrame
* aFrame
, nsFrameList
& aList
,
744 bool aCollectFromSiblings
) {
745 if (MaybeHasFloats()) {
746 DoCollectFloats(aFrame
, aList
, aCollectFromSiblings
);
749 void DoCollectFloats(nsIFrame
* aFrame
, nsFrameList
& aList
,
750 bool aCollectFromSiblings
);
752 // Remove a float, abs, rel positioned frame from the appropriate block's list
753 static void DoRemoveOutOfFlowFrame(DestroyContext
&, nsIFrame
*);
755 /** set up the conditions necessary for an resize reflow
756 * the primary task is to mark the minimumly sufficient lines dirty.
758 void PrepareResizeReflow(BlockReflowState
& aState
);
761 * Reflow all lines that have been marked dirty.
762 * Returns whether an overflow-wrap break was used anywhere.
764 bool ReflowDirtyLines(BlockReflowState
& aState
);
766 /** Mark a given line dirty due to reflow being interrupted on or before it */
767 void MarkLineDirtyForInterrupt(nsLineBox
* aLine
);
769 //----------------------------------------
770 // Methods for line reflow
775 * the current reflow input
777 * the line to reflow. can contain a single block frame or contain 1 or
778 * more inline frames.
779 * @param aKeepReflowGoing [OUT]
780 * indicates whether the caller should continue to reflow more lines
782 * whether an overflow-wrap breakpoint was used
784 bool ReflowLine(BlockReflowState
& aState
, LineIterator aLine
,
785 bool* aKeepReflowGoing
);
787 // Return false if it needs another reflow because of reduced space
788 // between floats that are next to it (but not next to its top), and
789 // return true otherwise.
790 bool PlaceLine(BlockReflowState
& aState
, nsLineLayout
& aLineLayout
,
792 nsFloatManager::SavedState
* aFloatStateBeforeLine
,
793 nsFlowAreaRect
& aFlowArea
, // in-out
794 nscoord
& aAvailableSpaceBSize
, // in-out
795 bool* aKeepReflowGoing
);
798 * If NS_BLOCK_LOOK_FOR_DIRTY_FRAMES is set, call MarkLineDirty
799 * on any line with a child frame that is dirty.
801 void LazyMarkLinesDirty();
804 * Mark |aLine| dirty, and, if necessary because of possible
805 * pull-up, mark the previous line dirty as well. Also invalidates textruns
806 * on those lines because the text in the lines might have changed due to
807 * addition/removal of frames.
808 * @param aLine the line to mark dirty
809 * @param aLineList the line list containing that line
811 void MarkLineDirty(LineIterator aLine
, const nsLineList
* aLineList
);
814 bool IsLastLine(BlockReflowState
& aState
, LineIterator aLine
);
816 void DeleteLine(BlockReflowState
& aState
, nsLineList::iterator aLine
,
817 nsLineList::iterator aLineEnd
);
819 //----------------------------------------
820 // Methods for individual frame reflow
822 bool ShouldApplyBStartMargin(BlockReflowState
& aState
, nsLineBox
* aLine
);
824 void ReflowBlockFrame(BlockReflowState
& aState
, LineIterator aLine
,
827 // Returns whether an overflow-wrap break was used.
828 bool ReflowInlineFrames(BlockReflowState
& aState
, LineIterator aLine
,
829 bool* aKeepLineGoing
);
831 void DoReflowInlineFrames(
832 BlockReflowState
& aState
, nsLineLayout
& aLineLayout
, LineIterator aLine
,
833 nsFlowAreaRect
& aFloatAvailableSpace
, nscoord
& aAvailableSpaceBSize
,
834 nsFloatManager::SavedState
* aFloatStateBeforeLine
, bool* aKeepReflowGoing
,
835 LineReflowStatus
* aLineReflowStatus
, bool aAllowPullUp
);
837 void ReflowInlineFrame(BlockReflowState
& aState
, nsLineLayout
& aLineLayout
,
838 LineIterator aLine
, nsIFrame
* aFrame
,
839 LineReflowStatus
* aLineReflowStatus
);
841 // @param aReflowStatus an incomplete status indicates the float should be
842 // split but only if the available block-size is constrained.
843 void ReflowFloat(BlockReflowState
& aState
, ReflowInput
& aFloatRI
,
844 nsIFrame
* aFloat
, nsReflowStatus
& aReflowStatus
);
846 //----------------------------------------
847 // Methods for pushing/pulling lines/frames
850 * Create a next-in-flow, if necessary, for aFrame. If a new frame is
851 * created, place it in aLine if aLine is not null.
852 * @param aState the block reflow state
853 * @param aLine where to put a new frame
854 * @param aFrame the frame
855 * @return true if a new frame was created, false if not
857 bool CreateContinuationFor(BlockReflowState
& aState
, nsLineBox
* aLine
,
861 * Set line-break-before status in aState.mReflowStatus because aLine cannot
862 * be placed on this page/column and we don't want to break within ourselves.
863 * Also, mark the aLine dirty, and set aKeepReflowGoing to false;
865 void SetBreakBeforeStatusBeforeLine(BlockReflowState
& aState
,
867 bool* aKeepReflowGoing
);
870 * Indicates if we need to compute a page name for the next page when pushing
873 * Using a value of No saves work when a new page name has already been set
874 * with nsCSSFrameConstructor::SetNextPageContentFramePageName.
876 enum class ComputeNewPageNameIfNeeded
: uint8_t { Yes
, No
};
879 * Push aLine (and any after it), since it cannot be placed on this
880 * page/column. Set aKeepReflowGoing to false and set
881 * flag aState.mReflowStatus as incomplete.
883 void PushTruncatedLine(BlockReflowState
& aState
, LineIterator aLine
,
884 bool* aKeepReflowGoing
,
885 ComputeNewPageNameIfNeeded aComputeNewPageName
=
886 ComputeNewPageNameIfNeeded::Yes
);
888 void SplitLine(BlockReflowState
& aState
, nsLineLayout
& aLineLayout
,
889 LineIterator aLine
, nsIFrame
* aFrame
,
890 LineReflowStatus
* aLineReflowStatus
);
893 * Pull a frame from the next available location (one of our lines or
894 * one of our next-in-flows lines).
895 * @return the pulled frame or nullptr
897 nsIFrame
* PullFrame(BlockReflowState
& aState
, LineIterator aLine
);
900 * Try to pull a frame out of a line pointed at by aFromLine.
902 * Note: pulling a frame from a line that is a place-holder frame
903 * doesn't automatically remove the corresponding float from the
904 * line's float array. This happens indirectly: either the line gets
905 * emptied (and destroyed) or the line gets reflowed (because we mark
906 * it dirty) and the code at the top of ReflowLine empties the
907 * array. So eventually, it will be removed, just not right away.
909 * @return the pulled frame or nullptr
911 nsIFrame
* PullFrameFrom(nsLineBox
* aLine
, nsBlockFrame
* aFromContainer
,
912 nsLineList::iterator aFromLine
);
915 * Push the line after aLineBefore to the overflow line list.
916 * @param aLineBefore a line in 'mLines' (or LinesBegin() when
917 * pushing the first line)
919 void PushLines(BlockReflowState
& aState
, nsLineList::iterator aLineBefore
);
921 void PropagateFloatDamage(BlockReflowState
& aState
, nsLineBox
* aLine
,
922 nscoord aDeltaBCoord
);
924 void CheckFloats(BlockReflowState
& aState
);
926 //----------------------------------------
927 // List handling kludge
929 void ReflowOutsideMarker(nsIFrame
* aMarkerFrame
, BlockReflowState
& aState
,
930 ReflowOutput
& aMetrics
, nscoord aLineTop
);
932 //----------------------------------------
934 NS_DECLARE_FRAME_PROPERTY_DELETABLE(LineIteratorProperty
, nsLineIterator
);
936 bool CanProvideLineIterator() const final
{ return true; }
937 nsILineIterator
* GetLineIterator() final
;
940 bool HasOverflowLines() const {
941 return HasAnyStateBits(NS_BLOCK_HAS_OVERFLOW_LINES
);
943 FrameLines
* GetOverflowLines() const;
946 FrameLines
* RemoveOverflowLines();
947 void SetOverflowLines(FrameLines
* aOverflowLines
);
948 void DestroyOverflowLines();
951 * This class is useful for efficiently modifying the out of flow
952 * overflow list. It gives the client direct writable access to
953 * the frame list temporarily but ensures that property is only
954 * written back if absolutely necessary.
956 struct nsAutoOOFFrameList
{
959 explicit nsAutoOOFFrameList(nsBlockFrame
* aBlock
)
960 : mPropValue(aBlock
->GetOverflowOutOfFlows()), mBlock(aBlock
) {
962 mList
= std::move(*mPropValue
);
965 ~nsAutoOOFFrameList() {
966 mBlock
->SetOverflowOutOfFlows(std::move(mList
), mPropValue
);
970 nsFrameList
* const mPropValue
;
971 nsBlockFrame
* const mBlock
;
973 friend struct nsAutoOOFFrameList
;
975 nsFrameList
* GetOverflowOutOfFlows() const;
977 // This takes ownership of the frames in aList.
978 void SetOverflowOutOfFlows(nsFrameList
&& aList
, nsFrameList
* aPropValue
);
981 * @return the inside ::marker frame or nullptr if we don't have one.
983 nsIFrame
* GetInsideMarker() const;
986 * @return the outside ::marker frame or nullptr if we don't have one.
988 nsIFrame
* GetOutsideMarker() const;
991 * @return the outside ::marker frame list frame property.
993 nsFrameList
* GetOutsideMarkerList() const;
996 * @return true if this frame has pushed floats.
998 bool HasPushedFloats() const {
999 return HasAnyStateBits(NS_BLOCK_HAS_PUSHED_FLOATS
);
1002 // Get the pushed floats list, which is used for *temporary* storage
1003 // of floats during reflow, between when we decide they don't fit in
1004 // this block until our next continuation takes them.
1005 nsFrameList
* GetPushedFloats() const;
1006 // Get the pushed floats list, or if there is not currently one,
1007 // make a new empty one.
1008 nsFrameList
* EnsurePushedFloats();
1009 // Remove and return the pushed floats list.
1010 nsFrameList
* RemovePushedFloats();
1013 void VerifyLines(bool aFinalCheckOK
);
1014 void VerifyOverflowSituation();
1015 int32_t GetDepth() const;
1018 nscoord mCachedMinISize
= NS_INTRINSIC_ISIZE_UNKNOWN
;
1019 nscoord mCachedPrefISize
= NS_INTRINSIC_ISIZE_UNKNOWN
;
1023 // List of all floats in this block
1024 // XXXmats blocks rarely have floats, make it a frame property
1025 nsFrameList mFloats
;
1027 friend class mozilla::BlockReflowState
;
1028 friend class nsBlockInFlowLineIterator
;
1032 static bool gLamePaintMetrics
;
1033 static bool gLameReflowMetrics
;
1035 static bool gNoisyDamageRepair
;
1036 static bool gNoisyIntrinsic
;
1037 static bool gNoisyReflow
;
1038 static bool gReallyNoisyReflow
;
1039 static bool gNoisyFloatManager
;
1040 static bool gVerifyLines
;
1041 static bool gDisableResizeOpt
;
1043 static int32_t gNoiseIndent
;
1045 static const char* kReflowCommandType
[];
1048 static void InitDebugFlags();
1053 class AutoNoisyIndenter
{
1055 explicit AutoNoisyIndenter(bool aDoIndent
) : mIndented(aDoIndent
) {
1057 nsBlockFrame::gNoiseIndent
++;
1060 ~AutoNoisyIndenter() {
1062 nsBlockFrame::gNoiseIndent
--;
1072 * Iterates over all lines in the prev-in-flows/next-in-flows of this block.
1074 class nsBlockInFlowLineIterator
{
1076 typedef nsBlockFrame::LineIterator LineIterator
;
1078 * Set up the iterator to point to aLine which must be a normal line
1079 * in aFrame (not an overflow line).
1081 nsBlockInFlowLineIterator(nsBlockFrame
* aFrame
, LineIterator aLine
);
1083 * Set up the iterator to point to the first line found starting from
1084 * aFrame. Sets aFoundValidLine to false if there is no such line.
1085 * After aFoundValidLine has returned false, don't call any methods on this
1088 nsBlockInFlowLineIterator(nsBlockFrame
* aFrame
, bool* aFoundValidLine
);
1090 * Set up the iterator to point to the line that contains aFindFrame (either
1091 * directly or indirectly). If aFrame is out of flow, or contained in an
1092 * out-of-flow, finds the line containing the out-of-flow's placeholder. If
1093 * the frame is not found, sets aFoundValidLine to false. After
1094 * aFoundValidLine has returned false, don't call any methods on this
1097 nsBlockInFlowLineIterator(nsBlockFrame
* aFrame
, nsIFrame
* aFindFrame
,
1098 bool* aFoundValidLine
);
1100 // Allow to be uninitialized (and then assigned from another object).
1101 nsBlockInFlowLineIterator() : mFrame(nullptr) {}
1103 LineIterator
GetLine() { return mLine
; }
1104 bool IsLastLineInList();
1105 nsBlockFrame
* GetContainer() { return mFrame
; }
1106 bool GetInOverflow() { return mLineList
!= &mFrame
->mLines
; }
1109 * Returns the current line list we're iterating, null means
1110 * we're iterating |mLines| of the container.
1112 nsLineList
* GetLineList() { return mLineList
; }
1115 * Returns the end-iterator of whatever line list we're in.
1120 * Returns false if there are no more lines. After this has returned false,
1121 * don't call any methods on this object again.
1125 * Returns false if there are no more lines. After this has returned false,
1126 * don't call any methods on this object again.
1130 // XXX nsBlockFrame uses this internally in one place. Try to remove it.
1131 // XXX uhm, and nsBidiPresUtils::Resolve too.
1132 nsBlockInFlowLineIterator(nsBlockFrame
* aFrame
, LineIterator aLine
,
1136 nsBlockFrame
* mFrame
;
1138 nsLineList
* mLineList
; // the line list mLine is in
1141 * Moves iterator to next valid line reachable from the current block.
1142 * Returns false if there are no valid lines.
1144 bool FindValidLine();
1147 #endif /* nsBlockFrame_h___ */