Merge autoland to mozilla-central. a=merge
[gecko.git] / layout / generic / nsBlockFrame.h
blobad3e3b9773da722214be6249975a45301dd512ab
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
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.
24 OK,
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.
27 Stop,
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.
30 RedoNoPull,
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.
34 RedoMoreFloats,
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.
37 RedoNextBand,
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
40 // page/column.
41 Truncated
44 class nsBlockInFlowLineIterator;
45 namespace mozilla {
46 class BlockReflowState;
47 class PresShell;
48 class ServoRestyleState;
49 class ServoStyleSet;
50 } // namespace mozilla
52 /**
53 * Some invariants:
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
65 * prev-in-flows.
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;
84 public:
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);
112 // nsQueryFrame
113 NS_DECL_QUERYFRAME
115 // nsIFrame
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;
155 #endif
157 #ifdef DEBUG
158 const char* LineReflowStatusToString(
159 LineReflowStatus aLineReflowStatus) const;
160 #endif
162 #ifdef ACCESSIBILITY
163 mozilla::a11y::AccType AccessibleType() override;
164 #endif
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);
197 ClearLineIterator();
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
224 // left untouched.)
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;
238 // Return true if this frame has a ::marker frame.
239 bool HasMarker() const { return HasOutsideMarker() || HasInsideMarker(); }
241 // Return true if this frame has an inside ::marker frame.
242 bool HasInsideMarker() const {
243 return HasAnyStateBits(NS_BLOCK_HAS_INSIDE_MARKER);
246 // Return true if this frame has an outside ::marker frame.
247 bool HasOutsideMarker() const {
248 return HasAnyStateBits(NS_BLOCK_HAS_OUTSIDE_MARKER);
252 * @return the first-letter frame or nullptr if we don't have one.
254 nsIFrame* GetFirstLetter() const;
257 * @return the ::first-line frame or nullptr if we don't have one.
259 nsIFrame* GetFirstLineFrame() const;
261 void MarkIntrinsicISizesDirty() override;
263 private:
264 // Whether CSS text-indent should be applied to the given line.
265 bool TextIndentAppliesTo(const LineIterator& aLine) const;
267 void CheckIntrinsicCacheAgainstShrinkWrapState();
269 template <typename LineIteratorType>
270 Maybe<nscoord> GetBaselineBOffset(LineIteratorType aStart,
271 LineIteratorType aEnd,
272 mozilla::WritingMode aWM,
273 BaselineSharingGroup aBaselineGroup,
274 BaselineExportContext aExportContext) const;
276 // MinISize() and PrefISize() are helpers to implement IntrinsicISize().
277 nscoord MinISize(const mozilla::IntrinsicSizeInput& aInput);
278 nscoord PrefISize(const mozilla::IntrinsicSizeInput& aInput);
280 public:
281 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
282 mozilla::IntrinsicISizeType aType) override;
284 nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;
286 nsresult GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX,
287 nscoord* aXMost) override;
290 * Compute the final block size of this frame.
292 * @param aState BlockReflowState passed from parent during reflow.
293 * Note: aState.mReflowStatus is mostly an "input" parameter. When this
294 * method is called, it should represent what our status would be as if
295 * we were shrinkwrapping our children's block-size. This method will
296 * then adjust it before returning if our status is different in light
297 * of our actual final block-size and current page/column's available
298 * block-size.
299 * @param aBEndEdgeOfChildren The distance between this frame's block-start
300 * border-edge and the block-end edge of our last child's border-box.
301 * This is effectively our block-start border-padding plus the
302 * block-size of our children, precomputed outside of this function.
303 * @return our final block-size with respect to aReflowInput's writing-mode.
305 nscoord ComputeFinalBSize(BlockReflowState& aState,
306 nscoord aBEndEdgeOfChildren);
308 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
309 const ReflowInput& aReflowInput,
310 nsReflowStatus& aStatus) override;
313 * Move any frames on our overflow list to the end of our principal list.
314 * @return true if there were any overflow frames
316 bool DrainSelfOverflowList() override;
318 void StealFrame(nsIFrame* aChild) override;
320 void DeleteNextInFlowChild(DestroyContext&, nsIFrame* aNextInFlow,
321 bool aDeletingEmptyFrames) override;
324 * This is a special method that allows a child class of nsBlockFrame to
325 * return a special, customized nsStyleText object to the nsLineLayout
326 * constructor. It is used when the nsBlockFrame child needs to specify its
327 * custom rendering style.
329 virtual const nsStyleText* StyleTextForLineLayout();
332 * Determines whether the collapsed margin carried out of the last
333 * line includes the margin-top of a line with clearance (in which
334 * case we must avoid collapsing that margin with our bottom margin)
336 bool CheckForCollapsedBEndMarginFromClearanceLine();
338 static nsresult GetCurrentLine(BlockReflowState* aState,
339 nsLineBox** aOutCurrentLine);
342 * Determine if this block is a margin root at the top/bottom edges.
344 void IsMarginRoot(bool* aBStartMarginRoot, bool* aBEndMarginRoot);
346 static bool BlockNeedsFloatManager(nsIFrame* aBlock);
349 * Returns whether aFrame is a block frame that will wrap its contents
350 * around floats intruding on it from the outside. (aFrame need not
351 * be a block frame, but if it's not, the result will be false.)
353 * Note: We often use the term "float-avoiding block" to refer to
354 * block-level frames for whom this function returns false.
356 static bool BlockCanIntersectFloats(nsIFrame* aFrame);
359 * Returns the inline size that needs to be cleared past floats for
360 * blocks that avoid (i.e. cannot intersect) floats. aState must already
361 * have GetFloatAvailableSpace called on it for the block-dir position that
362 * we care about (which need not be its current mBCoord)
364 struct FloatAvoidingISizeToClear {
365 // Note that we care about the inline-start margin but can ignore
366 // the inline-end margin.
367 nscoord marginIStart, borderBoxISize;
369 static FloatAvoidingISizeToClear ISizeToClearPastFloats(
370 const BlockReflowState& aState,
371 const mozilla::LogicalRect& aFloatAvailableSpace,
372 nsIFrame* aFloatAvoidingBlock);
375 * Creates a contination for aFloat and adds it to the list of overflow
376 * floats. Also updates aState.mReflowStatus to include the float's
377 * incompleteness. Must only be called while this block frame is in reflow.
378 * aFloatStatus must be the float's true, unmodified reflow status.
380 void SplitFloat(BlockReflowState& aState, nsIFrame* aFloat,
381 const nsReflowStatus& aFloatStatus);
384 * Walks up the frame tree, starting with aCandidate, and returns the first
385 * block frame that it encounters.
387 static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate);
389 struct FrameLines {
390 nsLineList mLines;
391 nsFrameList mFrames;
395 * Update the styles of our various pseudo-elements (marker, first-line,
396 * etc, but _not_ first-letter).
398 void UpdatePseudoElementStyles(mozilla::ServoRestyleState& aRestyleState);
400 // Update our first-letter styles during stylo post-traversal. This needs to
401 // be done at a slightly different time than our other pseudo-elements.
402 void UpdateFirstLetterStyle(mozilla::ServoRestyleState& aRestyleState);
404 protected:
405 explicit nsBlockFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
406 ClassID aID = kClassID)
407 : nsContainerFrame(aStyle, aPresContext, aID) {
408 #ifdef DEBUG
409 InitDebugFlags();
410 #endif
413 virtual ~nsBlockFrame();
415 void DidSetComputedStyle(ComputedStyle* aOldStyle) override;
417 #ifdef DEBUG
418 already_AddRefed<ComputedStyle> GetFirstLetterStyle(
419 nsPresContext* aPresContext);
420 #endif
422 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorPropertyDisplay, nsLineBox)
423 NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorPropertyQuery, nsLineBox)
424 // Note that the NS_BLOCK_HAS_LINE_CURSOR flag does not necessarily mean the
425 // cursor is present, as it covers both the "display" and "query" cursors,
426 // but may remain set if they have been separately deleted. In such a case,
427 // the Get* accessors will be slightly more expensive, but will still safely
428 // return null if the cursor is absent.
429 bool MaybeHasLineCursor() {
430 return HasAnyStateBits(NS_BLOCK_HAS_LINE_CURSOR);
432 nsLineBox* GetLineCursorForDisplay() {
433 return MaybeHasLineCursor() ? GetProperty(LineCursorPropertyDisplay())
434 : nullptr;
436 nsLineBox* GetLineCursorForQuery() {
437 return MaybeHasLineCursor() ? GetProperty(LineCursorPropertyQuery())
438 : nullptr;
441 void SetLineCursorForDisplay(nsLineBox* aLine) {
442 MOZ_ASSERT(aLine, "must have a line");
443 MOZ_ASSERT(!mLines.empty(), "aLine isn't my line");
444 SetProperty(LineCursorPropertyDisplay(), aLine);
445 AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
448 nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
449 return NS_NewLineBox(PresShell(), aFrame, aIsBlock);
451 nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame,
452 int32_t aCount) {
453 return NS_NewLineBox(PresShell(), aFromLine, aFrame, aCount);
455 void FreeLineBox(nsLineBox* aLine) {
456 if (aLine == GetLineCursorForDisplay()) {
457 ClearLineCursorForDisplay();
459 if (aLine == GetLineCursorForQuery()) {
460 ClearLineCursorForQuery();
462 aLine->Destroy(PresShell());
465 * Helper method for StealFrame.
467 void RemoveFrameFromLine(nsIFrame* aChild, nsLineList::iterator aLine,
468 nsFrameList& aFrameList, nsLineList& aLineList);
470 void TryAllLines(nsLineList::iterator* aIterator,
471 nsLineList::iterator* aStartIterator,
472 nsLineList::iterator* aEndIterator, bool* aInOverflowLines,
473 FrameLines** aOverflowLines);
475 /** move the frames contained by aLine by aDeltaBCoord
476 * if aLine is a block, its child floats are added to the state manager
478 void SlideLine(BlockReflowState& aState, nsLineBox* aLine,
479 nscoord aDeltaBCoord);
481 void UpdateLineContainerSize(nsLineBox* aLine,
482 const nsSize& aNewContainerSize);
484 // helper for SlideLine and UpdateLineContainerSize
485 void MoveChildFramesOfLine(nsLineBox* aLine, nscoord aDeltaBCoord);
487 // Returns block-end edge of children.
488 nscoord ComputeFinalSize(const ReflowInput& aReflowInput,
489 BlockReflowState& aState, ReflowOutput& aMetrics);
492 * Calculates the necessary shift to honor 'align-content' and applies it.
494 void AlignContent(BlockReflowState& aState, ReflowOutput& aMetrics,
495 nscoord aBEndEdgeOfChildren);
496 // Stash the effective align-content shift value between reflows
497 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(AlignContentShift, nscoord)
500 * Helper method for Reflow(). Computes the overflow areas created by our
501 * children, and includes them into aOverflowAreas.
503 void ComputeOverflowAreas(mozilla::OverflowAreas& aOverflowAreas,
504 nscoord aBEndEdgeOfChildren,
505 const nsStyleDisplay* aDisplay) const;
508 * Helper method for ComputeOverflowAreas(). Incorporates aBEndEdgeOfChildren
509 * into the aOverflowAreas.
511 void ConsiderBlockEndEdgeOfChildren(mozilla::OverflowAreas& aOverflowAreas,
512 nscoord aBEndEdgeOfChildren,
513 const nsStyleDisplay* aDisplay) const;
516 * Add the frames in aFrameList to this block after aPrevSibling.
517 * This block thinks in terms of lines, but the frame construction code
518 * knows nothing about lines at all so we need to find the line that
519 * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
520 * New lines are created as necessary to handle block data in aFrameList.
521 * This function will clear aFrameList.
523 * aPrevSiblingLine, if present, must be the line containing aPrevSibling.
524 * Providing it will make this function faster.
526 void AddFrames(nsFrameList&& aFrameList, nsIFrame* aPrevSibling,
527 const nsLineList::iterator* aPrevSiblingLine);
529 // Return the :-moz-block-ruby-content child frame, if any.
530 // (It's non-null only if this block frame is for 'display:block ruby'.)
531 nsContainerFrame* GetRubyContentPseudoFrame();
534 * Perform Bidi resolution on this frame
536 nsresult ResolveBidi();
539 * Test whether the frame is a form control in a visual Bidi page.
540 * This is necessary for backwards-compatibility, because most visual
541 * pages use logical order for form controls so that they will
542 * display correctly on native widgets in OSs with Bidi support
543 * @param aPresContext the pres context
544 * @return whether the frame is a BIDI form control
546 bool IsVisualFormControl(nsPresContext* aPresContext);
548 /** Whether this block has an effective align-content property */
549 bool IsAligned() const {
550 return StylePosition()->mAlignContent.primary !=
551 mozilla::StyleAlignFlags::NORMAL;
554 nscoord GetAlignContentShift() const {
555 return IsAligned() ? GetProperty(AlignContentShift()) : 0;
559 * For text-wrap:balance, we iteratively try reflowing with adjusted inline
560 * size to find the "best" result (the tightest size that can be applied
561 * without increasing the total line count of the block).
562 * This record is used to manage the state of these "trial reflows", and
563 * return results from the final trial.
565 struct TrialReflowState {
566 // Values pre-computed at start of Reflow(), constant across trials.
567 const nscoord mConsumedBSize;
568 const nscoord mEffectiveContentBoxBSize;
569 bool mNeedFloatManager;
570 // [out] Whether reflowing resulted in use of an overflow-wrap break.
571 bool mUsedOverflowWrap = false;
572 // Settings for the current trial.
573 bool mBalancing = false;
574 nscoord mInset = 0;
575 // Results computed during the trial reflow. Values from the final trial
576 // will be used by the remainder of Reflow().
577 mozilla::OverflowAreas mOcBounds;
578 mozilla::OverflowAreas mFcBounds;
579 nscoord mBlockEndEdgeOfChildren = 0;
580 nscoord mContainerWidth = 0;
582 // Initialize for the initial trial reflow, with zero inset.
583 TrialReflowState(nscoord aConsumedBSize, nscoord aEffectiveContentBoxBSize,
584 bool aNeedFloatManager)
585 : mConsumedBSize(aConsumedBSize),
586 mEffectiveContentBoxBSize(aEffectiveContentBoxBSize),
587 mNeedFloatManager(aNeedFloatManager) {}
589 // Adjust the inset amount, and reset state for a new trial.
590 void ResetForBalance(nscoord aInsetDelta) {
591 // Tells the reflow-lines loop we must consider all lines "dirty" (as we
592 // are modifying the effective inline-size to be used).
593 mBalancing = true;
594 // Adjust inset to apply.
595 mInset += aInsetDelta;
596 // Re-initialize state that the reflow loop will compute.
597 mOcBounds.Clear();
598 mFcBounds.Clear();
599 mBlockEndEdgeOfChildren = 0;
600 mContainerWidth = 0;
601 mUsedOverflowWrap = false;
606 * Internal helper for Reflow(); may be called repeatedly during a single
607 * Reflow() in order to implement text-wrap:balance.
608 * This method applies aTrialState.mInset during line-breaking to reduce
609 * the effective available inline-size (without affecting alignment).
611 nsReflowStatus TrialReflow(nsPresContext* aPresContext,
612 ReflowOutput& aMetrics,
613 const ReflowInput& aReflowInput,
614 TrialReflowState& aTrialState);
616 public:
618 * Helper function for the frame ctor to register a ::marker frame.
620 void SetMarkerFrameForListItem(nsIFrame* aMarkerFrame);
623 * Does all the real work for removing aDeletedFrame
624 * -- finds the line containing aDeletedFrame
625 * -- removes all aDeletedFrame next-in-flows (or all continuations,
626 * if REMOVE_FIXED_CONTINUATIONS is given)
627 * -- marks lines dirty as needed
628 * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
629 * case textruns do not need to be dirtied)
630 * -- destroys all removed frames
632 enum { REMOVE_FIXED_CONTINUATIONS = 0x02, FRAMES_ARE_EMPTY = 0x04 };
633 void DoRemoveFrame(DestroyContext&, nsIFrame* aDeletedFrame, uint32_t aFlags);
635 void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
636 bool aReparentSiblings);
638 bool ComputeCustomOverflow(mozilla::OverflowAreas&) override;
640 void UnionChildOverflow(mozilla::OverflowAreas&, bool aAsIfScrolled) override;
643 * Load all of aFrame's floats into the float manager iff aFrame is not a
644 * block formatting context. Handles all necessary float manager translations;
645 * assumes float manager is in aFrame's parent's coord system.
647 * Safe to call on non-blocks (does nothing).
649 static void RecoverFloatsFor(nsIFrame* aFrame, nsFloatManager& aFloatManager,
650 mozilla::WritingMode aWM,
651 const nsSize& aContainerSize);
654 * Determine if we have any pushed floats from a previous continuation.
656 * @returns true, if any of the floats at the beginning of our floats list
657 * have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise.
659 bool HasPushedFloatsFromPrevContinuation() const;
661 // @see nsIFrame::AddSizeOfExcludingThisForTree
662 void AddSizeOfExcludingThisForTree(nsWindowSizes&) const override;
665 * Clears any -webkit-line-clamp ellipsis on a line in this block or one
666 * of its descendants.
668 void ClearLineClampEllipsis();
671 * Returns whether this block is in a -webkit-line-clamp context. That is,
672 * whether this block is in a block formatting-context whose root block has
673 * -webkit-line-clamp: <n>.
675 bool IsInLineClampContext() const;
678 * @return false iff this block does not have a float on any child list.
679 * This function is O(1).
681 bool MaybeHasFloats() const;
683 protected:
684 /** grab overflow lines from this block's prevInFlow, and make them
685 * part of this block's mLines list.
686 * @return true if any lines were drained.
688 bool DrainOverflowLines();
691 * Moves frames from our PushedFloats list back into our mFloats list.
693 void DrainSelfPushedFloats();
696 * First calls DrainSelfPushedFloats() then grabs pushed floats from this
697 * block's prev-in-flow, and splice them into this block's mFloats list too.
699 void DrainPushedFloats();
701 /** Load all our floats into the float manager (without reflowing them).
702 * Assumes float manager is in our own coordinate system.
704 void RecoverFloats(nsFloatManager& aFloatManager, mozilla::WritingMode aWM,
705 const nsSize& aContainerSize);
707 /** Reflow pushed floats
709 void ReflowPushedFloats(BlockReflowState& aState,
710 mozilla::OverflowAreas& aOverflowAreas);
713 * Find any trailing BR clear from the last line of this block (or from its
714 * prev-in-flows).
716 mozilla::StyleClear FindTrailingClear();
719 * Remove a float from our float list.
721 void RemoveFloat(nsIFrame* aFloat);
723 * Remove a float from the float cache for the line its placeholder is on.
725 void RemoveFloatFromFloatCache(nsIFrame* aFloat);
727 void CollectFloats(nsIFrame* aFrame, nsFrameList& aList,
728 bool aCollectFromSiblings) {
729 if (MaybeHasFloats()) {
730 DoCollectFloats(aFrame, aList, aCollectFromSiblings);
733 void DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList,
734 bool aCollectFromSiblings);
736 // Remove a float, abs, rel positioned frame from the appropriate block's list
737 static void DoRemoveOutOfFlowFrame(DestroyContext&, nsIFrame*);
739 /** set up the conditions necessary for an resize reflow
740 * the primary task is to mark the minimumly sufficient lines dirty.
742 void PrepareResizeReflow(BlockReflowState& aState);
745 * Reflow all lines that have been marked dirty.
746 * Returns whether an overflow-wrap break was used anywhere.
748 bool ReflowDirtyLines(BlockReflowState& aState);
750 /** Mark a given line dirty due to reflow being interrupted on or before it */
751 void MarkLineDirtyForInterrupt(nsLineBox* aLine);
753 //----------------------------------------
754 // Methods for line reflow
756 * Reflow a line.
758 * @param aState
759 * the current reflow input
760 * @param aLine
761 * the line to reflow. can contain a single block frame or contain 1 or
762 * more inline frames.
763 * @param aKeepReflowGoing [OUT]
764 * indicates whether the caller should continue to reflow more lines
765 * @returns
766 * whether an overflow-wrap breakpoint was used
768 bool ReflowLine(BlockReflowState& aState, LineIterator aLine,
769 bool* aKeepReflowGoing);
771 // Return false if it needs another reflow because of reduced space
772 // between floats that are next to it (but not next to its top), and
773 // return true otherwise.
774 bool PlaceLine(BlockReflowState& aState, nsLineLayout& aLineLayout,
775 LineIterator aLine,
776 nsFloatManager::SavedState* aFloatStateBeforeLine,
777 nsFlowAreaRect& aFlowArea, // in-out
778 nscoord& aAvailableSpaceBSize, // in-out
779 bool* aKeepReflowGoing);
782 * If NS_BLOCK_LOOK_FOR_DIRTY_FRAMES is set, call MarkLineDirty
783 * on any line with a child frame that is dirty.
785 void LazyMarkLinesDirty();
788 * Mark |aLine| dirty, and, if necessary because of possible
789 * pull-up, mark the previous line dirty as well. Also invalidates textruns
790 * on those lines because the text in the lines might have changed due to
791 * addition/removal of frames.
792 * @param aLine the line to mark dirty
793 * @param aLineList the line list containing that line
795 void MarkLineDirty(LineIterator aLine, const nsLineList* aLineList);
797 // XXX where to go
798 bool IsLastLine(BlockReflowState& aState, LineIterator aLine);
800 void DeleteLine(BlockReflowState& aState, nsLineList::iterator aLine,
801 nsLineList::iterator aLineEnd);
803 //----------------------------------------
804 // Methods for individual frame reflow
806 bool ShouldApplyBStartMargin(BlockReflowState& aState, nsLineBox* aLine);
808 void ReflowBlockFrame(BlockReflowState& aState, LineIterator aLine,
809 bool* aKeepGoing);
811 // Returns whether an overflow-wrap break was used.
812 bool ReflowInlineFrames(BlockReflowState& aState, LineIterator aLine,
813 bool* aKeepLineGoing);
815 void DoReflowInlineFrames(
816 BlockReflowState& aState, nsLineLayout& aLineLayout, LineIterator aLine,
817 nsFlowAreaRect& aFloatAvailableSpace, nscoord& aAvailableSpaceBSize,
818 nsFloatManager::SavedState* aFloatStateBeforeLine, bool* aKeepReflowGoing,
819 LineReflowStatus* aLineReflowStatus, bool aAllowPullUp);
821 void ReflowInlineFrame(BlockReflowState& aState, nsLineLayout& aLineLayout,
822 LineIterator aLine, nsIFrame* aFrame,
823 LineReflowStatus* aLineReflowStatus);
825 // @param aReflowStatus an incomplete status indicates the float should be
826 // split but only if the available block-size is constrained.
827 void ReflowFloat(BlockReflowState& aState, ReflowInput& aFloatRI,
828 nsIFrame* aFloat, nsReflowStatus& aReflowStatus);
830 //----------------------------------------
831 // Methods for pushing/pulling lines/frames
834 * Create a next-in-flow, if necessary, for aFrame. If a new frame is
835 * created, place it in aLine if aLine is not null.
836 * @param aState the block reflow state
837 * @param aLine where to put a new frame
838 * @param aFrame the frame
839 * @return true if a new frame was created, false if not
841 bool CreateContinuationFor(BlockReflowState& aState, nsLineBox* aLine,
842 nsIFrame* aFrame);
845 * Set line-break-before status in aState.mReflowStatus because aLine cannot
846 * be placed on this page/column and we don't want to break within ourselves.
847 * Also, mark the aLine dirty, and set aKeepReflowGoing to false;
849 void SetBreakBeforeStatusBeforeLine(BlockReflowState& aState,
850 LineIterator aLine,
851 bool* aKeepReflowGoing);
854 * Indicates if we need to compute a page name for the next page when pushing
855 * a truncated line.
857 * Using a value of No saves work when a new page name has already been set
858 * with nsCSSFrameConstructor::SetNextPageContentFramePageName.
860 enum class ComputeNewPageNameIfNeeded : uint8_t { Yes, No };
863 * Push aLine (and any after it), since it cannot be placed on this
864 * page/column. Set aKeepReflowGoing to false and set
865 * flag aState.mReflowStatus as incomplete.
867 void PushTruncatedLine(BlockReflowState& aState, LineIterator aLine,
868 bool* aKeepReflowGoing,
869 ComputeNewPageNameIfNeeded aComputeNewPageName =
870 ComputeNewPageNameIfNeeded::Yes);
872 void SplitLine(BlockReflowState& aState, nsLineLayout& aLineLayout,
873 LineIterator aLine, nsIFrame* aFrame,
874 LineReflowStatus* aLineReflowStatus);
877 * Pull a frame from the next available location (one of our lines or
878 * one of our next-in-flows lines).
879 * @return the pulled frame or nullptr
881 nsIFrame* PullFrame(BlockReflowState& aState, LineIterator aLine);
884 * Try to pull a frame out of a line pointed at by aFromLine.
886 * Note: pulling a frame from a line that is a place-holder frame
887 * doesn't automatically remove the corresponding float from the
888 * line's float array. This happens indirectly: either the line gets
889 * emptied (and destroyed) or the line gets reflowed (because we mark
890 * it dirty) and the code at the top of ReflowLine empties the
891 * array. So eventually, it will be removed, just not right away.
893 * @return the pulled frame or nullptr
895 nsIFrame* PullFrameFrom(nsLineBox* aLine, nsBlockFrame* aFromContainer,
896 nsLineList::iterator aFromLine);
899 * Push the line after aLineBefore to the overflow line list.
900 * @param aLineBefore a line in 'mLines' (or LinesBegin() when
901 * pushing the first line)
903 void PushLines(BlockReflowState& aState, nsLineList::iterator aLineBefore);
905 void PropagateFloatDamage(BlockReflowState& aState, nsLineBox* aLine,
906 nscoord aDeltaBCoord);
908 void CheckFloats(BlockReflowState& aState);
910 //----------------------------------------
911 // List handling kludge
913 void ReflowOutsideMarker(nsIFrame* aMarkerFrame, BlockReflowState& aState,
914 ReflowOutput& aMetrics, nscoord aLineTop);
916 //----------------------------------------
918 NS_DECLARE_FRAME_PROPERTY_DELETABLE(LineIteratorProperty, nsLineIterator);
920 bool CanProvideLineIterator() const final { return true; }
921 nsILineIterator* GetLineIterator() final;
923 public:
924 bool HasOverflowLines() const {
925 return HasAnyStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
927 FrameLines* GetOverflowLines() const;
929 protected:
930 FrameLines* RemoveOverflowLines();
931 void SetOverflowLines(FrameLines* aOverflowLines);
932 void DestroyOverflowLines();
935 * This class is useful for efficiently modifying the out of flow
936 * overflow list. It gives the client direct writable access to
937 * the frame list temporarily but ensures that property is only
938 * written back if absolutely necessary.
940 struct nsAutoOOFFrameList {
941 nsFrameList mList;
943 explicit nsAutoOOFFrameList(nsBlockFrame* aBlock)
944 : mPropValue(aBlock->GetOverflowOutOfFlows()), mBlock(aBlock) {
945 if (mPropValue) {
946 mList = std::move(*mPropValue);
949 ~nsAutoOOFFrameList() {
950 mBlock->SetOverflowOutOfFlows(std::move(mList), mPropValue);
953 protected:
954 nsFrameList* const mPropValue;
955 nsBlockFrame* const mBlock;
957 friend struct nsAutoOOFFrameList;
959 nsFrameList* GetOverflowOutOfFlows() const;
961 // This takes ownership of the frames in aList.
962 void SetOverflowOutOfFlows(nsFrameList&& aList, nsFrameList* aPropValue);
964 // Return the ::marker frame or nullptr if we don't have one.
965 nsIFrame* GetMarker() const {
966 nsIFrame* outside = GetOutsideMarker();
967 return outside ? outside : GetInsideMarker();
970 // Return the inside ::marker frame or nullptr if we don't have one.
971 nsIFrame* GetInsideMarker() const;
973 // Return the outside ::marker frame or nullptr if we don't have one.
974 nsIFrame* GetOutsideMarker() const;
976 // Return the outside ::marker frame list frame property.
977 nsFrameList* GetOutsideMarkerList() const;
979 // Return true if this frame has floats.
980 bool HasFloats() const;
982 // Get the floats list, or nullptr if there isn't one.
983 nsFrameList* GetFloats() const;
985 // Get the floats list, or if there is not currently one, make a new empty
986 // one.
987 nsFrameList* EnsureFloats() MOZ_NONNULL_RETURN;
989 // Get the float list and remove the property from this frame.
991 // The caller is responsible for deleting the returned list and managing the
992 // ownership of all frames in the list.
993 [[nodiscard]] nsFrameList* StealFloats();
995 // Return true if this frame has pushed floats.
996 bool HasPushedFloats() const;
998 // Get the pushed floats list, or nullptr if there isn't one.
1000 // The pushed floats list is used for *temporary* storage of floats during
1001 // reflow, between when we decide they don't fit in this block until our next
1002 // continuation takes them.
1003 nsFrameList* GetPushedFloats() const;
1005 // Get the pushed floats list, or if there is not currently one,
1006 // make a new empty one.
1007 nsFrameList* EnsurePushedFloats() MOZ_NONNULL_RETURN;
1009 // Get the pushed float list and remove the property from this frame.
1011 // The caller is responsible for deleting the returned list and managing the
1012 // ownership of all frames in the list.
1013 [[nodiscard]] nsFrameList* StealPushedFloats();
1015 #ifdef DEBUG
1016 void VerifyLines(bool aFinalCheckOK);
1017 void VerifyOverflowSituation();
1018 int32_t GetDepth() const;
1019 #endif
1021 nscoord mCachedMinISize = NS_INTRINSIC_ISIZE_UNKNOWN;
1022 nscoord mCachedPrefISize = NS_INTRINSIC_ISIZE_UNKNOWN;
1024 nsLineList mLines;
1026 friend class mozilla::BlockReflowState;
1027 friend class nsBlockInFlowLineIterator;
1029 #ifdef DEBUG
1030 public:
1031 static bool gLamePaintMetrics;
1032 static bool gLameReflowMetrics;
1033 static bool gNoisy;
1034 static bool gNoisyDamageRepair;
1035 static bool gNoisyIntrinsic;
1036 static bool gNoisyReflow;
1037 static bool gReallyNoisyReflow;
1038 static bool gNoisyFloatManager;
1039 static bool gVerifyLines;
1040 static bool gDisableResizeOpt;
1042 static int32_t gNoiseIndent;
1044 static const char* kReflowCommandType[];
1046 protected:
1047 static void InitDebugFlags();
1048 #endif
1051 #ifdef DEBUG
1052 class AutoNoisyIndenter {
1053 public:
1054 explicit AutoNoisyIndenter(bool aDoIndent) : mIndented(aDoIndent) {
1055 if (mIndented) {
1056 nsBlockFrame::gNoiseIndent++;
1059 ~AutoNoisyIndenter() {
1060 if (mIndented) {
1061 nsBlockFrame::gNoiseIndent--;
1065 private:
1066 bool mIndented;
1068 #endif
1071 * Iterates over all lines in the prev-in-flows/next-in-flows of this block.
1073 class nsBlockInFlowLineIterator {
1074 public:
1075 typedef nsBlockFrame::LineIterator LineIterator;
1077 * Set up the iterator to point to aLine which must be a normal line
1078 * in aFrame (not an overflow line).
1080 nsBlockInFlowLineIterator(nsBlockFrame* aFrame, LineIterator aLine);
1082 * Set up the iterator to point to the first line found starting from
1083 * aFrame. Sets aFoundValidLine to false if there is no such line.
1084 * After aFoundValidLine has returned false, don't call any methods on this
1085 * object again.
1087 nsBlockInFlowLineIterator(nsBlockFrame* aFrame, bool* aFoundValidLine);
1089 * Set up the iterator to point to the line that contains aFindFrame (either
1090 * directly or indirectly). If aFrame is out of flow, or contained in an
1091 * out-of-flow, finds the line containing the out-of-flow's placeholder. If
1092 * the frame is not found, sets aFoundValidLine to false. After
1093 * aFoundValidLine has returned false, don't call any methods on this
1094 * object again.
1096 nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame,
1097 bool* aFoundValidLine);
1099 // Allow to be uninitialized (and then assigned from another object).
1100 nsBlockInFlowLineIterator() : mFrame(nullptr) {}
1102 LineIterator GetLine() { return mLine; }
1103 bool IsLastLineInList();
1104 nsBlockFrame* GetContainer() { return mFrame; }
1105 bool GetInOverflow() { return mLineList != &mFrame->mLines; }
1108 * Returns the current line list we're iterating, null means
1109 * we're iterating |mLines| of the container.
1111 nsLineList* GetLineList() { return mLineList; }
1114 * Returns the end-iterator of whatever line list we're in.
1116 LineIterator End();
1119 * Returns false if there are no more lines. After this has returned false,
1120 * don't call any methods on this object again.
1122 bool Next();
1124 * Returns false if there are no more lines. After this has returned false,
1125 * don't call any methods on this object again.
1127 bool Prev();
1129 // XXX nsBlockFrame uses this internally in one place. Try to remove it.
1130 // XXX uhm, and nsBidiPresUtils::Resolve too.
1131 nsBlockInFlowLineIterator(nsBlockFrame* aFrame, LineIterator aLine,
1132 bool aInOverflow);
1134 private:
1135 nsBlockFrame* mFrame;
1136 LineIterator mLine;
1137 nsLineList* mLineList; // the line list mLine is in
1140 * Moves iterator to next valid line reachable from the current block.
1141 * Returns false if there are no valid lines.
1143 bool FindValidLine();
1146 #endif /* nsBlockFrame_h___ */