1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:cindent:ts=2:et:sw=2:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
8 * described herein are Copyright (c) International Business Machines Corporation, 2000.
9 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
11 * Date Modified by Description of modification
12 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
15 /* state and methods used while laying out a single line of a block frame */
17 #ifndef nsLineLayout_h___
18 #define nsLineLayout_h___
20 #include "nsLineBox.h"
21 #include "nsBlockReflowState.h"
24 #include "WritingModes.h"
31 nsLineLayout(nsPresContext
* aPresContext
,
32 nsFloatManager
* aFloatManager
,
33 const nsHTMLReflowState
* aOuterReflowState
,
34 const nsLineList::iterator
* aLine
);
37 void Init(nsBlockReflowState
* aState
, nscoord aMinLineBSize
,
38 int32_t aLineNumber
) {
40 mMinLineBSize
= aMinLineBSize
;
41 mLineNumber
= aLineNumber
;
44 int32_t GetLineNumber() const {
48 void BeginLineReflow(nscoord aICoord
, nscoord aBCoord
,
49 nscoord aISize
, nscoord aBSize
,
50 bool aImpactedByFloats
,
52 mozilla::WritingMode aWritingMode
,
53 nscoord aContainerWidth
);
58 * Called when a float has been placed. This method updates the
59 * inline frame and span data to account for any change in positions
60 * due to available space for the line boxes changing.
61 * @param aX/aY/aWidth/aHeight are the new available
62 * space rectangle, relative to the containing block.
63 * @param aFloatFrame the float frame that was placed.
65 void UpdateBand(const nsRect
& aNewAvailableSpace
,
66 nsIFrame
* aFloatFrame
);
68 void BeginSpan(nsIFrame
* aFrame
, const nsHTMLReflowState
* aSpanReflowState
,
69 nscoord aLeftEdge
, nscoord aRightEdge
, nscoord
* aBaseline
);
71 // Returns the width of the span
72 nscoord
EndSpan(nsIFrame
* aFrame
);
74 int32_t GetCurrentSpanCount() const;
76 void SplitLineTo(int32_t aNewCount
);
80 // Reflows the frame and returns the reflow status. aPushedFrame is true
81 // if the frame is pushed to the next line because it doesn't fit.
82 void ReflowFrame(nsIFrame
* aFrame
,
83 nsReflowStatus
& aReflowStatus
,
84 nsHTMLReflowMetrics
* aMetrics
,
87 void AddBulletFrame(nsIFrame
* aFrame
, const nsHTMLReflowMetrics
& aMetrics
);
89 void RemoveBulletFrame(nsIFrame
* aFrame
) {
94 * Place frames in the block direction (CSS property vertical-align)
96 void VerticalAlignLine();
98 bool TrimTrailingWhiteSpace();
101 * Place frames in the inline direction (CSS property text-align).
103 void TextAlignLine(nsLineBox
* aLine
, bool aIsLastLine
);
106 * Handle all the relative positioning in the line, compute the
107 * combined area (== overflow area) for the line, and handle view
108 * sizing/positioning and the setting of the overflow rect.
110 void RelativePositionFrames(nsOverflowAreas
& aOverflowAreas
);
112 // Support methods for word-wrapping during line reflow
114 void SetTextJustificationWeights(int32_t aNumSpaces
, int32_t aNumLetters
) {
115 mTextJustificationNumSpaces
= aNumSpaces
;
116 mTextJustificationNumLetters
= aNumLetters
;
120 * @return true if so far during reflow no non-empty content has been
121 * placed in the line (according to nsIFrame::IsEmpty())
123 bool LineIsEmpty() const
129 * @return true if so far during reflow no non-empty leaf content
130 * (non-collapsed whitespace, replaced element, inline-block, etc) has been
133 bool LineAtStart() const
138 bool LineIsBreakable() const;
140 bool GetLineEndsInBR() const
142 return mLineEndsInBR
;
145 void SetLineEndsInBR(bool aOn
)
150 //----------------------------------------
151 // Inform the line-layout about the presence of a floating frame
152 // XXX get rid of this: use get-frame-type?
153 bool AddFloat(nsIFrame
* aFloat
, nscoord aAvailableWidth
)
155 return mBlockRS
->AddFloat(this, aFloat
, aAvailableWidth
);
158 void SetTrimmableWidth(nscoord aTrimmableWidth
) {
159 mTrimmableWidth
= aTrimmableWidth
;
162 //----------------------------------------
164 bool GetFirstLetterStyleOK() const {
165 return mFirstLetterStyleOK
;
168 void SetFirstLetterStyleOK(bool aSetting
) {
169 mFirstLetterStyleOK
= aSetting
;
172 bool GetInFirstLetter() const {
173 return mInFirstLetter
;
176 void SetInFirstLetter(bool aSetting
) {
177 mInFirstLetter
= aSetting
;
180 bool GetInFirstLine() const {
184 void SetInFirstLine(bool aSetting
) {
185 mInFirstLine
= aSetting
;
188 // Calling this during block reflow ensures that the next line of inlines
189 // will be marked dirty, if there is one.
190 void SetDirtyNextLine() {
191 mDirtyNextLine
= true;
193 bool GetDirtyNextLine() {
194 return mDirtyNextLine
;
197 //----------------------------------------
199 nsPresContext
* mPresContext
;
202 * Record where an optional break could have been placed. During line reflow,
203 * frames containing optional break points (e.g., whitespace in text frames)
204 * can call SetLastOptionalBreakPosition to record where a break could
205 * have been made, but wasn't because we decided to place more content on
206 * the line. For non-text frames, offset 0 means
207 * before the content, offset INT32_MAX means after the content.
209 * Currently this is used to handle cases where a single word comprises
210 * multiple frames, and the first frame fits on the line but the whole word
211 * doesn't. We look back to the last optional break position and
212 * reflow the whole line again, forcing a break at that position. The last
213 * optional break position could be in a text frame or else after a frame
214 * that cannot be part of a text run, so those are the positions we record.
216 * @param aFits set to true if the break position is within the available width.
218 * @param aPriority the priority of the break opportunity. If we are
219 * prioritizing break opportunities, we will not set a break if we have
220 * already set a break with a higher priority. @see gfxBreakPriority.
222 * @return true if we are actually reflowing with forced break position and we
225 bool NotifyOptionalBreakPosition(nsIContent
* aContent
, int32_t aOffset
,
226 bool aFits
, gfxBreakPriority aPriority
) {
227 NS_ASSERTION(!aFits
|| !mNeedBackup
,
228 "Shouldn't be updating the break position with a break that fits after we've already flagged an overrun");
229 // Remember the last break position that fits; if there was no break that fit,
230 // just remember the first break
231 if ((aFits
&& aPriority
>= mLastOptionalBreakPriority
) ||
232 !mLastOptionalBreakContent
) {
233 mLastOptionalBreakContent
= aContent
;
234 mLastOptionalBreakContentOffset
= aOffset
;
235 mLastOptionalBreakPriority
= aPriority
;
237 return aContent
&& mForceBreakContent
== aContent
&&
238 mForceBreakContentOffset
== aOffset
;
241 * Like NotifyOptionalBreakPosition, but here it's OK for mNeedBackup
242 * to be set, because the caller is merely pruning some saved break position(s)
243 * that are actually not feasible.
245 void RestoreSavedBreakPosition(nsIContent
* aContent
, int32_t aOffset
,
246 gfxBreakPriority aPriority
) {
247 mLastOptionalBreakContent
= aContent
;
248 mLastOptionalBreakContentOffset
= aOffset
;
249 mLastOptionalBreakPriority
= aPriority
;
252 * Signal that no backing up will be required after all.
254 void ClearOptionalBreakPosition() {
256 mLastOptionalBreakContent
= nullptr;
257 mLastOptionalBreakContentOffset
= -1;
258 mLastOptionalBreakPriority
= gfxBreakPriority::eNoBreak
;
260 // Retrieve last set optional break position. When this returns null, no
261 // optional break has been recorded (which means that the line can't break yet).
262 nsIContent
* GetLastOptionalBreakPosition(int32_t* aOffset
,
263 gfxBreakPriority
* aPriority
) {
264 *aOffset
= mLastOptionalBreakContentOffset
;
265 *aPriority
= mLastOptionalBreakPriority
;
266 return mLastOptionalBreakContent
;
270 * Check whether frames overflowed the available width and CanPlaceFrame
271 * requested backing up to a saved break position.
273 bool NeedsBackup() { return mNeedBackup
; }
275 // Line layout may place too much content on a line, overflowing its available
276 // width. When that happens, if SetLastOptionalBreakPosition has been
277 // used to record an optional break that wasn't taken, we can reflow the line
278 // again and force the break to happen at that point (i.e., backtracking
279 // to the last choice point).
281 // Record that we want to break at the given content+offset (which
282 // should have been previously returned by GetLastOptionalBreakPosition
283 // from another nsLineLayout).
284 void ForceBreakAtPosition(nsIContent
* aContent
, int32_t aOffset
) {
285 mForceBreakContent
= aContent
;
286 mForceBreakContentOffset
= aOffset
;
288 bool HaveForcedBreakPosition() { return mForceBreakContent
!= nullptr; }
289 int32_t GetForcedBreakPosition(nsIContent
* aContent
) {
290 return mForceBreakContent
== aContent
? mForceBreakContentOffset
: -1;
294 * This can't be null. It usually returns a block frame but may return
295 * some other kind of frame when inline frames are reflowed in a non-block
296 * context (e.g. MathML or floating first-letter).
298 nsIFrame
* LineContainerFrame() const { return mBlockReflowState
->frame
; }
299 const nsHTMLReflowState
* LineContainerRS() const { return mBlockReflowState
; }
300 const nsLineList::iterator
* GetLine() const {
301 return mGotLineBox
? &mLineBox
: nullptr;
303 nsLineList::iterator
* GetLine() {
304 return mGotLineBox
? &mLineBox
: nullptr;
308 * Returns the accumulated advance width of frames before the current frame
309 * on the line, plus the line container's left border+padding.
310 * This is always positive, the advance width is measured from
311 * the right edge for RTL blocks and from the left edge for LTR blocks.
312 * In other words, the current frame's distance from the line container's
313 * start content edge is:
314 * <code>GetCurrentFrameInlineDistanceFromBlock() - lineContainer->GetUsedBorderAndPadding().left</code>
315 * Note the use of <code>.left</code> for both LTR and RTL line containers.
317 nscoord
GetCurrentFrameInlineDistanceFromBlock();
320 * Move the inline position where the next frame will be reflowed forward by
323 void AdvanceICoord(nscoord aAmount
);
325 * Returns the writing mode for the root span.
327 mozilla::WritingMode
GetWritingMode();
329 * Returns the inline position where the next frame will be reflowed.
331 nscoord
GetCurrentICoord();
334 // This state is constant for a given block frame doing line layout
335 nsFloatManager
* mFloatManager
;
336 const nsStyleText
* mStyleText
; // for the block
337 const nsHTMLReflowState
* mBlockReflowState
;
339 nsIContent
* mLastOptionalBreakContent
;
340 nsIContent
* mForceBreakContent
;
342 // XXX remove this when landing bug 154892 (splitting absolute positioned frames)
343 friend class nsInlineFrame
;
345 nsBlockReflowState
* mBlockRS
;/* XXX hack! */
347 nsLineList::iterator mLineBox
;
349 // Per-frame data recorded by the line-layout reflow logic. This
350 // state is the state needed to post-process the line after reflow
351 // has completed (block-direction alignment, inline-direction alignment,
352 // justification and relative positioning).
356 friend struct PerSpanData
;
357 friend struct PerFrameData
;
360 explicit PerFrameData(mozilla::WritingMode aWritingMode
)
361 : mBounds(aWritingMode
)
362 , mMargin(aWritingMode
)
363 , mBorderPadding(aWritingMode
)
364 , mOffsets(aWritingMode
)
367 // link to next/prev frame in same span
371 // pointer to child span data if this is an inline container frame
379 // note that mBounds is a logical rect in the *line*'s writing mode.
380 // When setting frame coordinates, we have to convert to the frame's
382 mozilla::LogicalRect mBounds
;
383 nsOverflowAreas mOverflowAreas
;
386 mozilla::LogicalMargin mMargin
;
387 mozilla::LogicalMargin mBorderPadding
;
388 mozilla::LogicalMargin mOffsets
;
390 // state for text justification
391 int32_t mJustificationNumSpaces
;
392 int32_t mJustificationNumLetters
;
394 // Other state we use
395 uint8_t mBlockDirAlign
;
397 // PerFrameData flags
398 #define PFD_RELATIVEPOS 0x00000001
399 #define PFD_ISTEXTFRAME 0x00000002
400 #define PFD_ISNONEMPTYTEXTFRAME 0x00000004
401 #define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
402 #define PFD_ISLETTERFRAME 0x00000010
403 #define PFD_RECOMPUTEOVERFLOW 0x00000020
404 #define PFD_ISBULLET 0x00000040
405 #define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
406 #define PFD_LASTFLAG PFD_SKIPWHENTRIMMINGWHITESPACE
410 void SetFlag(uint32_t aFlag
, bool aValue
)
412 NS_ASSERTION(aFlag
<=PFD_LASTFLAG
, "bad flag");
413 NS_ASSERTION(aFlag
<=UINT8_MAX
, "bad flag");
414 if (aValue
) { // set flag
422 bool GetFlag(uint32_t aFlag
) const
424 NS_ASSERTION(aFlag
<=PFD_LASTFLAG
, "bad flag");
425 return !!(mFlags
& aFlag
);
429 PerFrameData
* Last() {
430 PerFrameData
* pfd
= this;
437 PerFrameData
* mFrameFreeList
;
441 PerSpanData
* mParent
;
442 PerSpanData
* mNextFreeSpan
;
444 PerFrameData
* mFrame
;
445 PerFrameData
* mFirstFrame
;
446 PerFrameData
* mLastFrame
;
448 const nsHTMLReflowState
* mReflowState
;
450 mozilla::WritingMode mWritingMode
;
451 bool mZeroEffectiveSpanBox
;
453 bool mHasNonemptyContent
;
459 nscoord mBStartLeading
, mBEndLeading
;
460 nscoord mLogicalBSize
;
461 nscoord mMinBCoord
, mMaxBCoord
;
464 void AppendFrame(PerFrameData
* pfd
) {
465 if (nullptr == mLastFrame
) {
469 mLastFrame
->mNext
= pfd
;
470 pfd
->mPrev
= mLastFrame
;
475 PerSpanData
* mSpanFreeList
;
476 PerSpanData
* mRootSpan
;
477 PerSpanData
* mCurrentSpan
;
479 gfxBreakPriority mLastOptionalBreakPriority
;
480 int32_t mLastOptionalBreakContentOffset
;
481 int32_t mForceBreakContentOffset
;
483 nscoord mMinLineBSize
;
485 // The amount of text indent that we applied to this line, needed for
486 // max-element-size calculation.
489 // This state varies during the reflow of a line but is line
490 // "global" state not span "local" state.
492 int32_t mTextJustificationNumSpaces
;
493 int32_t mTextJustificationNumLetters
;
495 int32_t mTotalPlacedFrames
;
498 nscoord mMaxStartBoxBSize
;
499 nscoord mMaxEndBoxBSize
;
501 nscoord mInflationMinFontSize
;
503 // Final computed line-bSize value after VerticalAlignFrames for
504 // the block has been called.
505 nscoord mFinalLineBSize
;
507 // Amount of trimmable whitespace width for the trailing text frame, if any
508 nscoord mTrimmableWidth
;
510 nscoord mContainerWidth
;
512 bool mFirstLetterStyleOK
: 1;
513 bool mIsTopOfPage
: 1;
514 bool mImpactedByFloats
: 1;
515 bool mLastFloatWasLetterFrame
: 1;
516 bool mLineIsEmpty
: 1;
517 bool mLineEndsInBR
: 1;
518 bool mNeedBackup
: 1;
519 bool mInFirstLine
: 1;
520 bool mGotLineBox
: 1;
521 bool mInFirstLetter
: 1;
523 bool mDirtyNextLine
: 1;
524 bool mLineAtStart
: 1;
528 int32_t mSpansAllocated
, mSpansFreed
;
529 int32_t mFramesAllocated
, mFramesFreed
;
531 PLArenaPool mArena
; // Per span and per frame data, 4 byte aligned
534 * Allocate a PerFrameData from the mArena pool. The allocation is infallible.
536 PerFrameData
* NewPerFrameData(nsIFrame
* aFrame
);
539 * Allocate a PerSpanData from the mArena pool. The allocation is infallible.
541 PerSpanData
* NewPerSpanData();
543 void FreeSpan(PerSpanData
* psd
);
545 bool InBlockContext() const {
546 return mSpanDepth
== 0;
549 void PushFrame(nsIFrame
* aFrame
);
551 void AllowForStartMargin(PerFrameData
* pfd
,
552 nsHTMLReflowState
& aReflowState
);
554 bool CanPlaceFrame(PerFrameData
* pfd
,
555 bool aNotSafeToBreak
,
556 bool aFrameCanContinueTextRun
,
557 bool aCanRollBackBeforeFrame
,
558 nsHTMLReflowMetrics
& aMetrics
,
559 nsReflowStatus
& aStatus
,
560 bool* aOptionalBreakAfterFits
);
562 void PlaceFrame(PerFrameData
* pfd
,
563 nsHTMLReflowMetrics
& aMetrics
);
565 void VerticalAlignFrames(PerSpanData
* psd
);
567 void PlaceTopBottomFrames(PerSpanData
* psd
,
568 nscoord aDistanceFromStart
,
571 void RelativePositionFrames(PerSpanData
* psd
, nsOverflowAreas
& aOverflowAreas
);
573 bool TrimTrailingWhiteSpaceIn(PerSpanData
* psd
, nscoord
* aDeltaISize
);
575 void ComputeJustificationWeights(PerSpanData
* psd
, int32_t* numSpaces
, int32_t* numLetters
);
577 struct FrameJustificationState
{
578 int32_t mTotalNumSpaces
;
579 int32_t mTotalNumLetters
;
580 nscoord mTotalWidthForSpaces
;
581 nscoord mTotalWidthForLetters
;
582 int32_t mNumSpacesProcessed
;
583 int32_t mNumLettersProcessed
;
584 nscoord mWidthForSpacesProcessed
;
585 nscoord mWidthForLettersProcessed
;
588 // Apply justification. The return value is the amount by which the width of
589 // the span corresponding to aPSD got increased due to justification.
590 nscoord
ApplyFrameJustification(PerSpanData
* aPSD
,
591 FrameJustificationState
* aState
);
595 void DumpPerSpanData(PerSpanData
* psd
, int32_t aIndent
);
599 #endif /* nsLineLayout_h___ */