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 /* state and methods used while laying out a single line of a block frame */
8 
9 #ifndef nsLineLayout_h___
10 #define nsLineLayout_h___
11 
12 #include "gfxTypes.h"
13 #include "JustificationUtils.h"
14 #include "mozilla/ArenaAllocator.h"
15 #include "mozilla/WritingModes.h"
16 #include "BlockReflowState.h"
17 #include "nsLineBox.h"
18 
19 class nsFloatManager;
20 struct nsStyleText;
21 
22 class nsLineLayout {
23   using BlockReflowState = mozilla::BlockReflowState;
24   using ReflowInput = mozilla::ReflowInput;
25   using ReflowOutput = mozilla::ReflowOutput;
26 
27  public:
28   /**
29    * @param aBaseLineLayout the nsLineLayout for ruby base,
30    * nullptr if no separate base nsLineLayout is needed.
31    */
32   nsLineLayout(nsPresContext* aPresContext, nsFloatManager* aFloatManager,
33                const ReflowInput& aLineContainerRI,
34                const nsLineList::iterator* aLine,
35                nsLineLayout* aBaseLineLayout);
36   ~nsLineLayout();
37 
Init(BlockReflowState * aState,nscoord aMinLineBSize,int32_t aLineNumber)38   void Init(BlockReflowState* aState, nscoord aMinLineBSize,
39             int32_t aLineNumber) {
40     mBlockRS = aState;
41     mMinLineBSize = aMinLineBSize;
42     mLineNumber = aLineNumber;
43   }
44 
GetLineNumber()45   int32_t GetLineNumber() const { return mLineNumber; }
46 
47   void BeginLineReflow(nscoord aICoord, nscoord aBCoord, nscoord aISize,
48                        nscoord aBSize, bool aImpactedByFloats,
49                        bool aIsTopOfPage, mozilla::WritingMode aWritingMode,
50                        const nsSize& aContainerSize);
51 
52   void EndLineReflow();
53 
54   /**
55    * Called when a float has been placed. This method updates the
56    * inline frame and span data to account for any change in positions
57    * due to available space for the line boxes changing.
58    * @param aX/aY/aWidth/aHeight are the new available
59    * space rectangle, relative to the containing block.
60    * @param aFloatFrame the float frame that was placed.
61    */
62   void UpdateBand(mozilla::WritingMode aWM,
63                   const mozilla::LogicalRect& aNewAvailableSpace,
64                   nsIFrame* aFloatFrame);
65 
66   void BeginSpan(nsIFrame* aFrame, const ReflowInput* aSpanReflowInput,
67                  nscoord aLeftEdge, nscoord aRightEdge, nscoord* aBaseline);
68 
69   // Returns the width of the span
70   nscoord EndSpan(nsIFrame* aFrame);
71 
72   // This method attaches the last frame reflowed in this line layout
73   // to that in the base line layout.
AttachLastFrameToBaseLineLayout()74   void AttachLastFrameToBaseLineLayout() {
75     AttachFrameToBaseLineLayout(LastFrame());
76   }
77 
78   // This method attaches the root frame of this line layout to the
79   // last reflowed frame in the base line layout.
AttachRootFrameToBaseLineLayout()80   void AttachRootFrameToBaseLineLayout() {
81     AttachFrameToBaseLineLayout(mRootSpan->mFrame);
82   }
83 
84   int32_t GetCurrentSpanCount() const;
85 
86   void SplitLineTo(int32_t aNewCount);
87 
88   bool IsZeroBSize();
89 
90   // Reflows the frame and returns the reflow status. aPushedFrame is true
91   // if the frame is pushed to the next line because it doesn't fit.
92   void ReflowFrame(nsIFrame* aFrame, nsReflowStatus& aReflowStatus,
93                    ReflowOutput* aMetrics, bool& aPushedFrame);
94 
95   void AddMarkerFrame(nsIFrame* aFrame, const ReflowOutput& aMetrics);
96 
97   void RemoveMarkerFrame(nsIFrame* aFrame);
98 
99   /**
100    * Place frames in the block direction (CSS property vertical-align)
101    */
102   void VerticalAlignLine();
103 
104   bool TrimTrailingWhiteSpace();
105 
106   /**
107    * Place frames in the inline direction (CSS property text-align).
108    */
109   void TextAlignLine(nsLineBox* aLine, bool aIsLastLine);
110 
111   /**
112    * Handle all the relative positioning in the line, compute the
113    * combined area (== overflow area) for the line, and handle view
114    * sizing/positioning and the setting of the overflow rect.
115    */
RelativePositionFrames(mozilla::OverflowAreas & aOverflowAreas)116   void RelativePositionFrames(mozilla::OverflowAreas& aOverflowAreas) {
117     RelativePositionFrames(mRootSpan, aOverflowAreas);
118   }
119 
120   // Support methods for word-wrapping during line reflow
121 
SetJustificationInfo(const mozilla::JustificationInfo & aInfo)122   void SetJustificationInfo(const mozilla::JustificationInfo& aInfo) {
123     mJustificationInfo = aInfo;
124   }
125 
126   /**
127    * @return true if so far during reflow no non-empty content has been
128    * placed in the line (according to nsIFrame::IsEmpty())
129    */
LineIsEmpty()130   bool LineIsEmpty() const { return mLineIsEmpty; }
131 
132   /**
133    * @return true if so far during reflow no non-empty leaf content
134    * (non-collapsed whitespace, replaced element, inline-block, etc) has been
135    * placed in the line
136    */
LineAtStart()137   bool LineAtStart() const { return mLineAtStart; }
138 
139   bool LineIsBreakable() const;
140 
GetLineEndsInBR()141   bool GetLineEndsInBR() const { return mLineEndsInBR; }
142 
SetLineEndsInBR(bool aOn)143   void SetLineEndsInBR(bool aOn) { mLineEndsInBR = aOn; }
144 
145   //----------------------------------------
146   // Inform the line-layout about the presence of a floating frame
147   // XXX get rid of this: use get-frame-type?
AddFloat(nsIFrame * aFloat,nscoord aAvailableISize)148   bool AddFloat(nsIFrame* aFloat, nscoord aAvailableISize) {
149     // When reflowing ruby text frames, no block reflow state is
150     // provided to the line layout. However, floats should never be
151     // associated with ruby text containers, hence this method should
152     // not be called in that case.
153     MOZ_ASSERT(mBlockRS,
154                "Should not call this method if there is no block reflow state "
155                "available");
156     return mBlockRS->AddFloat(this, aFloat, aAvailableISize);
157   }
158 
SetTrimmableISize(nscoord aTrimmableISize)159   void SetTrimmableISize(nscoord aTrimmableISize) {
160     mTrimmableISize = aTrimmableISize;
161   }
162 
163   //----------------------------------------
164 
GetFirstLetterStyleOK()165   bool GetFirstLetterStyleOK() const { return mFirstLetterStyleOK; }
166 
SetFirstLetterStyleOK(bool aSetting)167   void SetFirstLetterStyleOK(bool aSetting) { mFirstLetterStyleOK = aSetting; }
168 
GetInFirstLetter()169   bool GetInFirstLetter() const { return mInFirstLetter; }
170 
SetInFirstLetter(bool aSetting)171   void SetInFirstLetter(bool aSetting) { mInFirstLetter = aSetting; }
172 
GetInFirstLine()173   bool GetInFirstLine() const { return mInFirstLine; }
174 
SetInFirstLine(bool aSetting)175   void SetInFirstLine(bool aSetting) { mInFirstLine = aSetting; }
176 
177   // Calling this during block reflow ensures that the next line of inlines
178   // will be marked dirty, if there is one.
SetDirtyNextLine()179   void SetDirtyNextLine() { mDirtyNextLine = true; }
GetDirtyNextLine()180   bool GetDirtyNextLine() { return mDirtyNextLine; }
181 
182   //----------------------------------------
183 
184   nsPresContext* mPresContext;
185 
186   /**
187    * Record where an optional break could have been placed. During line reflow,
188    * frames containing optional break points (e.g., whitespace in text frames)
189    * can call SetLastOptionalBreakPosition to record where a break could
190    * have been made, but wasn't because we decided to place more content on
191    * the line. For non-text frames, offset 0 means before the frame, offset
192    * INT32_MAX means after the frame.
193    *
194    * Currently this is used to handle cases where a single word comprises
195    * multiple frames, and the first frame fits on the line but the whole word
196    * doesn't. We look back to the last optional break position and
197    * reflow the whole line again, forcing a break at that position. The last
198    * optional break position could be in a text frame or else after a frame
199    * that cannot be part of a text run, so those are the positions we record.
200    *
201    * @param aFrame the frame which contains the optional break position.
202    *
203    * @param aFits set to true if the break position is within the available
204    * width.
205    *
206    * @param aPriority the priority of the break opportunity. If we are
207    * prioritizing break opportunities, we will not set a break if we have
208    * already set a break with a higher priority. @see gfxBreakPriority.
209    *
210    * @return true if we are actually reflowing with forced break position and we
211    * should break here
212    */
213   bool NotifyOptionalBreakPosition(nsIFrame* aFrame, int32_t aOffset,
214                                    bool aFits, gfxBreakPriority aPriority);
215 
216   // Tries to place a float, and records whether the float actually was placed.
217   bool TryToPlaceFloat(nsIFrame* aFloat);
218 
219   // Records a floating frame in a nowrap context for it to be placed on the
220   // next break opportunity.
221   void RecordNoWrapFloat(nsIFrame* aFloat);
222 
223   // Tries to place the floats from the nowrap context.
224   void FlushNoWrapFloats();
225 
226   /**
227    * Like NotifyOptionalBreakPosition, but here it's OK for mNeedBackup
228    * to be set, because the caller is merely pruning some saved break
229    * position(s) that are actually not feasible.
230    */
RestoreSavedBreakPosition(nsIFrame * aFrame,int32_t aOffset,gfxBreakPriority aPriority)231   void RestoreSavedBreakPosition(nsIFrame* aFrame, int32_t aOffset,
232                                  gfxBreakPriority aPriority) {
233     mLastOptionalBreakFrame = aFrame;
234     mLastOptionalBreakFrameOffset = aOffset;
235     mLastOptionalBreakPriority = aPriority;
236   }
237   /**
238    * Signal that no backing up will be required after all.
239    */
ClearOptionalBreakPosition()240   void ClearOptionalBreakPosition() {
241     mNeedBackup = false;
242     mLastOptionalBreakFrame = nullptr;
243     mLastOptionalBreakFrameOffset = -1;
244     mLastOptionalBreakPriority = gfxBreakPriority::eNoBreak;
245   }
246   // Retrieve last set optional break position. When this returns null, no
247   // optional break has been recorded (which means that the line can't break
248   // yet).
GetLastOptionalBreakPosition(int32_t * aOffset,gfxBreakPriority * aPriority)249   nsIFrame* GetLastOptionalBreakPosition(int32_t* aOffset,
250                                          gfxBreakPriority* aPriority) {
251     *aOffset = mLastOptionalBreakFrameOffset;
252     *aPriority = mLastOptionalBreakPriority;
253     return mLastOptionalBreakFrame;
254   }
255   // Whether any optional break position has been recorded.
HasOptionalBreakPosition()256   bool HasOptionalBreakPosition() const {
257     return mLastOptionalBreakFrame != nullptr;
258   }
259   // Get the priority of the last optional break position recorded.
LastOptionalBreakPriority()260   gfxBreakPriority LastOptionalBreakPriority() const {
261     return mLastOptionalBreakPriority;
262   }
263 
264   /**
265    * Check whether frames overflowed the available width and CanPlaceFrame
266    * requested backing up to a saved break position.
267    */
NeedsBackup()268   bool NeedsBackup() { return mNeedBackup; }
269 
270   // Line layout may place too much content on a line, overflowing its available
271   // width. When that happens, if SetLastOptionalBreakPosition has been
272   // used to record an optional break that wasn't taken, we can reflow the line
273   // again and force the break to happen at that point (i.e., backtracking
274   // to the last choice point).
275 
276   // Record that we want to break at the given content+offset (which
277   // should have been previously returned by GetLastOptionalBreakPosition
278   // from another nsLineLayout).
ForceBreakAtPosition(nsIFrame * aFrame,int32_t aOffset)279   void ForceBreakAtPosition(nsIFrame* aFrame, int32_t aOffset) {
280     mForceBreakFrame = aFrame;
281     mForceBreakFrameOffset = aOffset;
282   }
HaveForcedBreakPosition()283   bool HaveForcedBreakPosition() { return mForceBreakFrame != nullptr; }
GetForcedBreakPosition(nsIFrame * aFrame)284   int32_t GetForcedBreakPosition(nsIFrame* aFrame) {
285     return mForceBreakFrame == aFrame ? mForceBreakFrameOffset : -1;
286   }
287 
288   /**
289    * This can't be null. It usually returns a block frame but may return
290    * some other kind of frame when inline frames are reflowed in a non-block
291    * context (e.g. MathML or floating first-letter).
292    */
LineContainerFrame()293   nsIFrame* LineContainerFrame() const { return mLineContainerRI.mFrame; }
LineContainerRI()294   const ReflowInput& LineContainerRI() const { return mLineContainerRI; }
GetLine()295   const nsLineList::iterator* GetLine() const {
296     return mGotLineBox ? &mLineBox : nullptr;
297   }
GetLine()298   nsLineList::iterator* GetLine() { return mGotLineBox ? &mLineBox : nullptr; }
299 
300   /**
301    * Returns the accumulated advance width of frames before the current frame
302    * on the line, plus the line container's left border+padding.
303    * This is always positive, the advance width is measured from
304    * the right edge for RTL blocks and from the left edge for LTR blocks.
305    * In other words, the current frame's distance from the line container's
306    * start content edge is:
307    * <code>GetCurrentFrameInlineDistanceFromBlock() -
308    * lineContainer->GetUsedBorderAndPadding().left</code> Note the use of
309    * <code>.left</code> for both LTR and RTL line containers.
310    */
311   nscoord GetCurrentFrameInlineDistanceFromBlock();
312 
313   /**
314    * Move the inline position where the next frame will be reflowed forward by
315    * aAmount.
316    */
AdvanceICoord(nscoord aAmount)317   void AdvanceICoord(nscoord aAmount) { mCurrentSpan->mICoord += aAmount; }
318   /**
319    * Returns the writing mode for the root span.
320    */
GetWritingMode()321   mozilla::WritingMode GetWritingMode() { return mRootSpan->mWritingMode; }
322   /**
323    * Returns the inline position where the next frame will be reflowed.
324    */
GetCurrentICoord()325   nscoord GetCurrentICoord() { return mCurrentSpan->mICoord; }
326 
SetSuppressLineWrap(bool aEnabled)327   void SetSuppressLineWrap(bool aEnabled) { mSuppressLineWrap = aEnabled; }
328 
329  protected:
330   // This state is constant for a given block frame doing line layout
331 
332   // A non-owning pointer, which points to the object owned by
333   // nsAutoFloatManager::mNew.
334   nsFloatManager* mFloatManager;
335 
336   const nsStyleText* mStyleText;  // for the block
337   const ReflowInput& mLineContainerRI;
338 
339   // The line layout for the base text.  It is usually nullptr.
340   // It becomes not null when the current line layout is for ruby
341   // annotations. When there is nested ruby inside annotation, it
342   // forms a linked list from the inner annotation to the outermost
343   // line layout. The outermost line layout, which has this member
344   // being nullptr, is responsible for managing the life cycle of
345   // per-frame data and per-span data, and handling floats.
346   nsLineLayout* const mBaseLineLayout;
347 
GetOutermostLineLayout()348   nsLineLayout* GetOutermostLineLayout() {
349     nsLineLayout* lineLayout = this;
350     while (lineLayout->mBaseLineLayout) {
351       lineLayout = lineLayout->mBaseLineLayout;
352     }
353     return lineLayout;
354   }
355 
356   nsIFrame* mLastOptionalBreakFrame;
357   nsIFrame* mForceBreakFrame;
358 
359   // XXX remove this when landing bug 154892 (splitting absolute positioned
360   // frames)
361   friend class nsInlineFrame;
362 
363   // XXX Take care that nsRubyBaseContainer would give nullptr to this
364   //     member. It should not be a problem currently, since the only
365   //     code use it is handling float, which does not affect ruby.
366   //     See comment in nsLineLayout::AddFloat
367   BlockReflowState* mBlockRS = nullptr; /* XXX hack! */
368 
369   nsLineList::iterator mLineBox;
370 
371   // Per-frame data recorded by the line-layout reflow logic. This
372   // state is the state needed to post-process the line after reflow
373   // has completed (block-direction alignment, inline-direction alignment,
374   // justification and relative positioning).
375 
376   struct PerSpanData;
377   struct PerFrameData;
378   friend struct PerSpanData;
379   friend struct PerFrameData;
380   struct PerFrameData {
381     // link to next/prev frame in same span
382     PerFrameData* mNext;
383     PerFrameData* mPrev;
384 
385     // Link to the frame of next ruby annotation.  It is a linked list
386     // through this pointer from ruby base to all its annotations.  It
387     // could be nullptr if there is no more annotation.
388     // If PFD_ISLINKEDTOBASE is set, the current PFD is one of the ruby
389     // annotations in the base's list, otherwise it is the ruby base,
390     // and its mNextAnnotation is the start of the linked list.
391     PerFrameData* mNextAnnotation;
392 
393     // pointer to child span data if this is an inline container frame
394     PerSpanData* mSpan;
395 
396     // The frame
397     nsIFrame* mFrame;
398 
399     // From metrics
400     nscoord mAscent;
401     // note that mBounds is a logical rect in the *line*'s writing mode.
402     // When setting frame coordinates, we have to convert to the frame's
403     //  writing mode
404     mozilla::LogicalRect mBounds;
405     mozilla::OverflowAreas mOverflowAreas;
406 
407     // From reflow-state
408     mozilla::LogicalMargin mMargin;         // in *line* writing mode
409     mozilla::LogicalMargin mBorderPadding;  // in *line* writing mode
410     mozilla::LogicalMargin mOffsets;        // in *frame* writing mode
411 
412     // state for text justification
413     // Note that, although all frames would have correct inner
414     // opportunities computed after ComputeFrameJustification, start
415     // and end justifiable info are not reliable for non-text frames.
416     mozilla::JustificationInfo mJustificationInfo;
417     mozilla::JustificationAssignment mJustificationAssignment;
418 
419     // PerFrameData flags
420     bool mIsRelativelyOrStickyPos : 1;
421     bool mIsTextFrame : 1;
422     bool mIsNonEmptyTextFrame : 1;
423     bool mIsNonWhitespaceTextFrame : 1;
424     bool mIsLetterFrame : 1;
425     bool mRecomputeOverflow : 1;
426     bool mIsMarker : 1;
427     bool mSkipWhenTrimmingWhitespace : 1;
428     bool mIsEmpty : 1;
429     bool mIsPlaceholder : 1;
430     bool mIsLinkedToBase : 1;
431 
432     // Other state we use
433     uint8_t mBlockDirAlign;
434     mozilla::WritingMode mWritingMode;
435 
LastPerFrameData436     PerFrameData* Last() {
437       PerFrameData* pfd = this;
438       while (pfd->mNext) {
439         pfd = pfd->mNext;
440       }
441       return pfd;
442     }
443 
IsStartJustifiablePerFrameData444     bool IsStartJustifiable() const {
445       return mJustificationInfo.mIsStartJustifiable;
446     }
447 
IsEndJustifiablePerFrameData448     bool IsEndJustifiable() const {
449       return mJustificationInfo.mIsEndJustifiable;
450     }
451 
452     bool ParticipatesInJustification() const;
453   };
454   PerFrameData* mFrameFreeList;
455 
456   // In nsLineLayout, a "span" is a container inline frame, and a "frame" is one
457   // of its children.
458   //
459   // nsLineLayout::BeginLineReflow() creates the initial PerSpanData which is
460   // called the "root span". nsInlineFrame::ReflowFrames() creates a new
461   // PerSpanData when it calls nsLineLayout::BeginSpan(); at this time, the
462   // nsLineLayout object's mCurrentSpan is switched to the new span. The new
463   // span records the old mCurrentSpan as its parent. After reflowing the child
464   // inline frames, nsInlineFrame::ReflowFrames() calls nsLineLayout::EndSpan(),
465   // which pops the PerSpanData and re-sets mCurrentSpan.
466   struct PerSpanData {
467     union {
468       PerSpanData* mParent;
469       PerSpanData* mNextFreeSpan;
470     };
471 
472     // The PerFrameData of the inline frame that "owns" the span, or null if
473     // this is the root span. mFrame is initialized to the containing inline
474     // frame's PerFrameData when a new PerSpanData is pushed in
475     // nsLineLayout::BeginSpan().
476     PerFrameData* mFrame;
477 
478     // The first PerFrameData structure in the span.
479     PerFrameData* mFirstFrame;
480 
481     // The last PerFrameData structure in the span. PerFrameData structures are
482     // added to the span as they are reflowed. mLastFrame may also be directly
483     // manipulated if a line is split, or if frames are pushed from one line to
484     // the next.
485     PerFrameData* mLastFrame;
486 
487     const ReflowInput* mReflowInput;
488     bool mNoWrap;
489     mozilla::WritingMode mWritingMode;
490     bool mContainsFloat;
491     bool mHasNonemptyContent;
492 
493     nscoord mIStart;
494     nscoord mICoord;
495     nscoord mIEnd;
496 
497     nscoord mBStartLeading, mBEndLeading;
498     nscoord mLogicalBSize;
499     nscoord mMinBCoord, mMaxBCoord;
500     nscoord* mBaseline;
501 
AppendFramePerSpanData502     void AppendFrame(PerFrameData* pfd) {
503       if (!mLastFrame) {
504         mFirstFrame = pfd;
505       } else {
506         mLastFrame->mNext = pfd;
507         pfd->mPrev = mLastFrame;
508       }
509       mLastFrame = pfd;
510     }
511   };
512   PerSpanData* mSpanFreeList;
513   PerSpanData* mRootSpan;
514   PerSpanData* mCurrentSpan;
515 
516   // The container size to use when converting between logical and
517   // physical coordinates for frames in this span. For the root span
518   // this is the size of the block cached in mContainerSize; for
519   // child spans it's the size of the root span.
ContainerSizeForSpan(PerSpanData * aPSD)520   nsSize ContainerSizeForSpan(PerSpanData* aPSD) {
521     return (aPSD == mRootSpan)
522                ? mContainerSize
523                : aPSD->mFrame->mBounds.Size(mRootSpan->mWritingMode)
524                      .GetPhysicalSize(mRootSpan->mWritingMode);
525   }
526 
527   gfxBreakPriority mLastOptionalBreakPriority;
528   int32_t mLastOptionalBreakFrameOffset;
529   int32_t mForceBreakFrameOffset;
530 
531   nscoord mMinLineBSize;
532 
533   // The amount of text indent that we applied to this line, needed for
534   // max-element-size calculation.
535   nscoord mTextIndent;
536 
537   // This state varies during the reflow of a line but is line
538   // "global" state not span "local" state.
539   int32_t mLineNumber;
540   mozilla::JustificationInfo mJustificationInfo;
541 
542   int32_t mTotalPlacedFrames;
543 
544   nscoord mBStartEdge;
545   nscoord mMaxStartBoxBSize;
546   nscoord mMaxEndBoxBSize;
547 
548   nscoord mInflationMinFontSize;
549 
550   // Final computed line-bSize value after VerticalAlignFrames for
551   // the block has been called.
552   nscoord mFinalLineBSize;
553 
554   // Amount of trimmable whitespace inline size for the trailing text
555   // frame, if any
556   nscoord mTrimmableISize;
557 
558   // Physical size. Use only for physical <-> logical coordinate conversion.
559   nsSize mContainerSize;
ContainerSize()560   const nsSize& ContainerSize() const { return mContainerSize; }
561 
562   bool mFirstLetterStyleOK : 1;
563   bool mIsTopOfPage : 1;
564   bool mImpactedByFloats : 1;
565   bool mLastFloatWasLetterFrame : 1;
566   bool mLineIsEmpty : 1;
567   bool mLineEndsInBR : 1;
568   bool mNeedBackup : 1;
569   bool mInFirstLine : 1;
570   bool mGotLineBox : 1;
571   bool mInFirstLetter : 1;
572   bool mHasMarker : 1;
573   bool mDirtyNextLine : 1;
574   bool mLineAtStart : 1;
575   bool mHasRuby : 1;
576   bool mSuppressLineWrap : 1;
577 
578   int32_t mSpanDepth;
579 #ifdef DEBUG
580   int32_t mSpansAllocated, mSpansFreed;
581   int32_t mFramesAllocated, mFramesFreed;
582 #endif
583 
584   /**
585    * Per span and per frame data.
586    */
587   mozilla::ArenaAllocator<1024, sizeof(void*)> mArena;
588 
589   /**
590    * Allocate a PerFrameData from the mArena pool. The allocation is infallible.
591    */
592   PerFrameData* NewPerFrameData(nsIFrame* aFrame);
593 
594   /**
595    * Allocate a PerSpanData from the mArena pool. The allocation is infallible.
596    */
597   PerSpanData* NewPerSpanData();
598 
LastFrame()599   PerFrameData* LastFrame() const { return mCurrentSpan->mLastFrame; }
600 
601   /**
602    * Unlink the given PerFrameData and all the siblings after it from
603    * the span. The unlinked PFDs are usually freed immediately.
604    * However, if PFD_ISLINKEDTOBASE is set, it won't be freed until
605    * the frame of its base is unlinked.
606    */
607   void UnlinkFrame(PerFrameData* pfd);
608 
609   /**
610    * Free the given PerFrameData.
611    */
612   void FreeFrame(PerFrameData* pfd);
613 
614   void FreeSpan(PerSpanData* psd);
615 
InBlockContext()616   bool InBlockContext() const { return mSpanDepth == 0; }
617 
618   void PushFrame(nsIFrame* aFrame);
619 
620   void AllowForStartMargin(PerFrameData* pfd, ReflowInput& aReflowInput);
621 
622   void SyncAnnotationBounds(PerFrameData* aRubyFrame);
623 
624   bool CanPlaceFrame(PerFrameData* pfd, bool aNotSafeToBreak,
625                      bool aFrameCanContinueTextRun,
626                      bool aCanRollBackBeforeFrame, ReflowOutput& aMetrics,
627                      nsReflowStatus& aStatus, bool* aOptionalBreakAfterFits);
628 
629   void PlaceFrame(PerFrameData* pfd, ReflowOutput& aMetrics);
630 
631   void AdjustLeadings(nsIFrame* spanFrame, PerSpanData* psd,
632                       const nsStyleText* aStyleText, float aInflation,
633                       bool* aZeroEffectiveSpanBox);
634 
635   void VerticalAlignFrames(PerSpanData* psd);
636 
637   void PlaceTopBottomFrames(PerSpanData* psd, nscoord aDistanceFromStart,
638                             nscoord aLineBSize);
639 
640   void ApplyRelativePositioning(PerFrameData* aPFD);
641 
642   void RelativePositionAnnotations(PerSpanData* aRubyPSD,
643                                    mozilla::OverflowAreas& aOverflowAreas);
644 
645   void RelativePositionFrames(PerSpanData* psd,
646                               mozilla::OverflowAreas& aOverflowAreas);
647 
648   bool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaISize);
649 
650   struct JustificationComputationState;
651 
652   static int AssignInterframeJustificationGaps(
653       PerFrameData* aFrame, JustificationComputationState& aState);
654 
655   int32_t ComputeFrameJustification(PerSpanData* psd,
656                                     JustificationComputationState& aState);
657 
658   void AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
659                                      const nsSize& aContainerSize,
660                                      nscoord aDeltaICoord, nscoord aDeltaISize);
661 
662   void ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
663                                            nscoord aDeltaICoord,
664                                            nscoord aDeltaISize);
665 
666   // Apply justification.  The return value is the amount by which the width of
667   // the span corresponding to aPSD got increased due to justification.
668   nscoord ApplyFrameJustification(
669       PerSpanData* aPSD, mozilla::JustificationApplicationState& aState);
670 
671   void ExpandRubyBox(PerFrameData* aFrame, nscoord aReservedISize,
672                      const nsSize& aContainerSize);
673 
674   void ExpandRubyBoxWithAnnotations(PerFrameData* aFrame,
675                                     const nsSize& aContainerSize);
676 
677   void ExpandInlineRubyBoxes(PerSpanData* aSpan);
678 
679   void AttachFrameToBaseLineLayout(PerFrameData* aFrame);
680 
681 #ifdef DEBUG
682   void DumpPerSpanData(PerSpanData* psd, int32_t aIndent);
683 #endif
684 };
685 
686 #endif /* nsLineLayout_h___ */
687