1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:cindent:ts=2:et:sw=2:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
25 * Steve Clark <buster@netscape.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK *****
40 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
41 * described herein are Copyright (c) International Business Machines Corporation, 2000.
42 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
44 * Date Modified by Description of modification
45 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
48 /* state and methods used while laying out a single line of a block frame */
50 #ifndef nsLineLayout_h___
51 #define nsLineLayout_h___
55 #include "nsLineBox.h"
56 #include "nsBlockReflowState.h"
63 class nsPlaceholderFrame
;
68 nsLineLayout(nsPresContext
* aPresContext
,
69 nsFloatManager
* aFloatManager
,
70 const nsHTMLReflowState
* aOuterReflowState
,
71 const nsLineList::iterator
* aLine
);
74 void Init(nsBlockReflowState
* aState
, nscoord aMinLineHeight
,
75 PRInt32 aLineNumber
) {
77 mMinLineHeight
= aMinLineHeight
;
78 mLineNumber
= aLineNumber
;
81 PRInt32
GetLineNumber() const {
85 void BeginLineReflow(nscoord aX
, nscoord aY
,
86 nscoord aWidth
, nscoord aHeight
,
87 PRBool aImpactedByFloats
,
93 * Called when a float has been placed. This method updates the
94 * inline frame and span data to account for any change in positions
95 * due to available space for the line boxes changing.
96 * @param aX/aY/aWidth/aHeight are the new available
97 * space rectangle, relative to the containing block.
98 * @param aFloatFrame the float frame that was placed.
100 void UpdateBand(const nsRect
& aNewAvailableSpace
,
101 nsIFrame
* aFloatFrame
);
103 nsresult
BeginSpan(nsIFrame
* aFrame
,
104 const nsHTMLReflowState
* aSpanReflowState
,
108 // Returns the width of the span
109 nscoord
EndSpan(nsIFrame
* aFrame
);
111 PRInt32
GetCurrentSpanCount() const;
113 void SplitLineTo(PRInt32 aNewCount
);
115 PRBool
IsZeroHeight();
117 // Reflows the frame and returns the reflow status. aPushedFrame is PR_TRUE
118 // if the frame is pushed to the next line because it doesn't fit
119 nsresult
ReflowFrame(nsIFrame
* aFrame
,
120 nsReflowStatus
& aReflowStatus
,
121 nsHTMLReflowMetrics
* aMetrics
,
122 PRBool
& aPushedFrame
);
124 nsresult
AddBulletFrame(nsIFrame
* aFrame
,
125 const nsHTMLReflowMetrics
& aMetrics
);
127 void RemoveBulletFrame(nsIFrame
* aFrame
) {
131 void VerticalAlignLine();
133 PRBool
TrimTrailingWhiteSpace();
135 void HorizontalAlignFrames(nsRect
& aLineBounds
, PRBool aAllowJustify
);
138 * Handle all the relative positioning in the line, compute the
139 * combined area (== overflow area) for the line, and handle view
140 * sizing/positioning and the setting of the overflow rect.
142 void RelativePositionFrames(nsOverflowAreas
& aOverflowAreas
);
144 //----------------------------------------
146 // Supporting methods and data for flags
148 #define LL_FIRSTLETTERSTYLEOK 0x00000008
149 #define LL_ISTOPOFPAGE 0x00000010
150 #define LL_IMPACTEDBYFLOATS 0x00000040
151 #define LL_LASTFLOATWASLETTERFRAME 0x00000080
152 #define LL_LINEISEMPTY 0x00000100
153 #define LL_LINEENDSINBR 0x00000200
154 #define LL_NEEDBACKUP 0x00000400
155 #define LL_INFIRSTLINE 0x00000800
156 #define LL_GOTLINEBOX 0x00001000
157 #define LL_INFIRSTLETTER 0x00002000
158 #define LL_HASBULLET 0x00004000
159 #define LL_DIRTYNEXTLINE 0x00008000
160 #define LL_LINEATSTART 0x00010000
161 #define LL_LASTFLAG LL_LINEATSTART
163 void SetFlag(PRUint32 aFlag
, PRBool aValue
)
165 NS_ASSERTION(aFlag
<=LL_LASTFLAG
, "bad flag");
166 NS_ASSERTION(aValue
==PR_FALSE
|| aValue
==PR_TRUE
, "bad value");
167 if (aValue
) { // set flag
175 PRBool
GetFlag(PRUint32 aFlag
) const
177 NS_ASSERTION(aFlag
<=LL_LASTFLAG
, "bad flag");
178 return !!(mFlags
& aFlag
);
183 // Support methods for word-wrapping during line reflow
185 void SetTextJustificationWeights(PRInt32 aNumSpaces
, PRInt32 aNumLetters
) {
186 mTextJustificationNumSpaces
= aNumSpaces
;
187 mTextJustificationNumLetters
= aNumLetters
;
191 * @return true if so far during reflow no non-empty content has been
192 * placed in the line (according to nsIFrame::IsEmpty())
194 PRBool
LineIsEmpty() const
196 return GetFlag(LL_LINEISEMPTY
);
200 * @return true if so far during reflow no non-empty leaf content
201 * (non-collapsed whitespace, replaced element, inline-block, etc) has been
204 PRBool
LineAtStart() const
206 return GetFlag(LL_LINEATSTART
);
209 PRBool
LineIsBreakable() const;
211 PRBool
GetLineEndsInBR() const
213 return GetFlag(LL_LINEENDSINBR
);
216 void SetLineEndsInBR(PRBool aOn
)
218 SetFlag(LL_LINEENDSINBR
, aOn
);
221 //----------------------------------------
222 // Inform the line-layout about the presence of a floating frame
223 // XXX get rid of this: use get-frame-type?
224 PRBool
AddFloat(nsIFrame
* aFloat
, nscoord aAvailableWidth
)
226 return mBlockRS
->AddFloat(this, aFloat
, aAvailableWidth
);
229 void SetTrimmableWidth(nscoord aTrimmableWidth
) {
230 mTrimmableWidth
= aTrimmableWidth
;
233 //----------------------------------------
235 PRBool
GetFirstLetterStyleOK() const {
236 return GetFlag(LL_FIRSTLETTERSTYLEOK
);
239 void SetFirstLetterStyleOK(PRBool aSetting
) {
240 SetFlag(LL_FIRSTLETTERSTYLEOK
, aSetting
);
243 PRBool
GetInFirstLetter() const {
244 return GetFlag(LL_INFIRSTLETTER
);
247 void SetInFirstLetter(PRBool aSetting
) {
248 SetFlag(LL_INFIRSTLETTER
, aSetting
);
251 PRBool
GetInFirstLine() const {
252 return GetFlag(LL_INFIRSTLINE
);
255 void SetInFirstLine(PRBool aSetting
) {
256 SetFlag(LL_INFIRSTLINE
, aSetting
);
259 // Calling this during block reflow ensures that the next line of inlines
260 // will be marked dirty, if there is one.
261 void SetDirtyNextLine() {
262 SetFlag(LL_DIRTYNEXTLINE
, PR_TRUE
);
264 PRBool
GetDirtyNextLine() {
265 return GetFlag(LL_DIRTYNEXTLINE
);
268 //----------------------------------------
270 nsPresContext
* mPresContext
;
273 * Record where an optional break could have been placed. During line reflow,
274 * frames containing optional break points (e.g., whitespace in text frames)
275 * can call SetLastOptionalBreakPosition to record where a break could
276 * have been made, but wasn't because we decided to place more content on
277 * the line. For non-text frames, offset 0 means
278 * before the content, offset PR_INT32_MAX means after the content.
280 * Currently this is used to handle cases where a single word comprises
281 * multiple frames, and the first frame fits on the line but the whole word
282 * doesn't. We look back to the last optional break position and
283 * reflow the whole line again, forcing a break at that position. The last
284 * optional break position could be in a text frame or else after a frame
285 * that cannot be part of a text run, so those are the positions we record.
287 * @param aFits set to true if the break position is within the available width.
289 * @param aPriority the priority of the break opportunity. If we are
290 * prioritizing break opportunities, we will not set a break if we have
291 * already set a break with a higher priority. @see gfxBreakPriority.
293 * @return PR_TRUE if we are actually reflowing with forced break position and we
296 PRBool
NotifyOptionalBreakPosition(nsIContent
* aContent
, PRInt32 aOffset
,
297 PRBool aFits
, gfxBreakPriority aPriority
) {
298 NS_ASSERTION(!aFits
|| !GetFlag(LL_NEEDBACKUP
),
299 "Shouldn't be updating the break position with a break that fits after we've already flagged an overrun");
300 // Remember the last break position that fits; if there was no break that fit,
301 // just remember the first break
302 if ((aFits
&& aPriority
>= mLastOptionalBreakPriority
) ||
303 !mLastOptionalBreakContent
) {
304 mLastOptionalBreakContent
= aContent
;
305 mLastOptionalBreakContentOffset
= aOffset
;
306 mLastOptionalBreakPriority
= aPriority
;
308 return aContent
&& mForceBreakContent
== aContent
&&
309 mForceBreakContentOffset
== aOffset
;
312 * Like NotifyOptionalBreakPosition, but here it's OK for LL_NEEDBACKUP
313 * to be set, because the caller is merely pruning some saved break position(s)
314 * that are actually not feasible.
316 void RestoreSavedBreakPosition(nsIContent
* aContent
, PRInt32 aOffset
,
317 gfxBreakPriority aPriority
) {
318 mLastOptionalBreakContent
= aContent
;
319 mLastOptionalBreakContentOffset
= aOffset
;
320 mLastOptionalBreakPriority
= aPriority
;
323 * Signal that no backing up will be required after all.
325 void ClearOptionalBreakPosition() {
326 SetFlag(LL_NEEDBACKUP
, PR_FALSE
);
327 mLastOptionalBreakContent
= nsnull
;
328 mLastOptionalBreakContentOffset
= -1;
329 mLastOptionalBreakPriority
= eNoBreak
;
331 // Retrieve last set optional break position. When this returns null, no
332 // optional break has been recorded (which means that the line can't break yet).
333 nsIContent
* GetLastOptionalBreakPosition(PRInt32
* aOffset
,
334 gfxBreakPriority
* aPriority
) {
335 *aOffset
= mLastOptionalBreakContentOffset
;
336 *aPriority
= mLastOptionalBreakPriority
;
337 return mLastOptionalBreakContent
;
341 * Check whether frames overflowed the available width and CanPlaceFrame
342 * requested backing up to a saved break position.
344 PRBool
NeedsBackup() { return GetFlag(LL_NEEDBACKUP
); }
346 // Line layout may place too much content on a line, overflowing its available
347 // width. When that happens, if SetLastOptionalBreakPosition has been
348 // used to record an optional break that wasn't taken, we can reflow the line
349 // again and force the break to happen at that point (i.e., backtracking
350 // to the last choice point).
352 // Record that we want to break at the given content+offset (which
353 // should have been previously returned by GetLastOptionalBreakPosition
354 // from another nsLineLayout).
355 void ForceBreakAtPosition(nsIContent
* aContent
, PRInt32 aOffset
) {
356 mForceBreakContent
= aContent
;
357 mForceBreakContentOffset
= aOffset
;
359 PRBool
HaveForcedBreakPosition() { return mForceBreakContent
!= nsnull
; }
360 PRInt32
GetForcedBreakPosition(nsIContent
* aContent
) {
361 return mForceBreakContent
== aContent
? mForceBreakContentOffset
: -1;
365 * This can't be null. It usually returns a block frame but may return
366 * some other kind of frame when inline frames are reflowed in a non-block
367 * context (e.g. MathML or floating first-letter).
369 nsIFrame
* GetLineContainerFrame() const { return mBlockReflowState
->frame
; }
370 const nsLineList::iterator
* GetLine() const {
371 return GetFlag(LL_GOTLINEBOX
) ? &mLineBox
: nsnull
;
373 nsLineList::iterator
* GetLine() {
374 return GetFlag(LL_GOTLINEBOX
) ? &mLineBox
: nsnull
;
378 * Returns the accumulated advance width of frames before the current frame
379 * on the line, plus the line container's left border+padding.
380 * This is always positive, the advance width is measured from
381 * the right edge for RTL blocks and from the left edge for LTR blocks.
382 * In other words, the current frame's distance from the line container's
383 * start content edge is:
384 * <code>GetCurrentFrameXDistanceFromBlock() - lineContainer->GetUsedBorderAndPadding().left</code>
385 * Note the use of <code>.left</code> for both LTR and RTL line containers.
387 nscoord
GetCurrentFrameXDistanceFromBlock();
390 // This state is constant for a given block frame doing line layout
391 nsFloatManager
* mFloatManager
;
392 const nsStyleText
* mStyleText
; // for the block
393 const nsHTMLReflowState
* mBlockReflowState
;
395 nsIContent
* mLastOptionalBreakContent
;
396 nsIContent
* mForceBreakContent
;
398 // XXX remove this when landing bug 154892 (splitting absolute positioned frames)
399 friend class nsInlineFrame
;
401 nsBlockReflowState
* mBlockRS
;/* XXX hack! */
403 nsLineList::iterator mLineBox
;
405 // Per-frame data recorded by the line-layout reflow logic. This
406 // state is the state needed to post-process the line after reflow
407 // has completed (vertical alignment, horizontal alignment,
408 // justification and relative positioning).
412 friend struct PerSpanData
;
413 friend struct PerFrameData
;
414 struct PerFrameData
{
415 // link to next/prev frame in same span
419 // pointer to child span data if this is an inline container frame
428 nsOverflowAreas mOverflowAreas
;
432 nsMargin mBorderPadding
;
435 // state for text justification
436 PRInt32 mJustificationNumSpaces
;
437 PRInt32 mJustificationNumLetters
;
439 // Other state we use
440 PRUint8 mVerticalAlign
;
442 // PerFrameData flags
443 #define PFD_RELATIVEPOS 0x00000001
444 #define PFD_ISTEXTFRAME 0x00000002
445 #define PFD_ISNONEMPTYTEXTFRAME 0x00000004
446 #define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
447 #define PFD_ISLETTERFRAME 0x00000010
448 #define PFD_RECOMPUTEOVERFLOW 0x00000020
449 #define PFD_ISBULLET 0x00000040
450 #define PFD_SKIPWHENTRIMMINGWHITESPACE 0x00000080
451 #define PFD_LASTFLAG PFD_SKIPWHENTRIMMINGWHITESPACE
455 void SetFlag(PRUint32 aFlag
, PRBool aValue
)
457 NS_ASSERTION(aFlag
<=PFD_LASTFLAG
, "bad flag");
458 NS_ASSERTION(aFlag
<=PR_UINT8_MAX
, "bad flag");
459 NS_ASSERTION(aValue
==PR_FALSE
|| aValue
==PR_TRUE
, "bad value");
460 if (aValue
) { // set flag
468 PRBool
GetFlag(PRUint32 aFlag
) const
470 NS_ASSERTION(aFlag
<=PFD_LASTFLAG
, "bad flag");
471 return !!(mFlags
& aFlag
);
475 PerFrameData
* Last() {
476 PerFrameData
* pfd
= this;
483 PerFrameData
* mFrameFreeList
;
487 PerSpanData
* mParent
;
488 PerSpanData
* mNextFreeSpan
;
490 PerFrameData
* mFrame
;
491 PerFrameData
* mFirstFrame
;
492 PerFrameData
* mLastFrame
;
494 const nsHTMLReflowState
* mReflowState
;
495 PRPackedBool mNoWrap
;
497 PRPackedBool mChangedFrameDirection
;
498 PRPackedBool mZeroEffectiveSpanBox
;
499 PRPackedBool mContainsFloat
;
500 PRPackedBool mHasNonemptyContent
;
506 nscoord mTopLeading
, mBottomLeading
;
507 nscoord mLogicalHeight
;
508 nscoord mMinY
, mMaxY
;
510 void AppendFrame(PerFrameData
* pfd
) {
511 if (nsnull
== mLastFrame
) {
515 mLastFrame
->mNext
= pfd
;
516 pfd
->mPrev
= mLastFrame
;
521 PerSpanData
* mSpanFreeList
;
522 PerSpanData
* mRootSpan
;
523 PerSpanData
* mCurrentSpan
;
525 gfxBreakPriority mLastOptionalBreakPriority
;
526 PRInt32 mLastOptionalBreakContentOffset
;
527 PRInt32 mForceBreakContentOffset
;
529 nscoord mMinLineHeight
;
531 // The amount of text indent that we applied to this line, needed for
532 // max-element-size calculation.
535 // This state varies during the reflow of a line but is line
536 // "global" state not span "local" state.
538 PRInt32 mTextJustificationNumSpaces
;
539 PRInt32 mTextJustificationNumLetters
;
541 PRInt32 mTotalPlacedFrames
;
544 nscoord mMaxTopBoxHeight
;
545 nscoord mMaxBottomBoxHeight
;
547 // Final computed line-height value after VerticalAlignFrames for
548 // the block has been called.
549 nscoord mFinalLineHeight
;
551 // Amount of trimmable whitespace width for the trailing text frame, if any
552 nscoord mTrimmableWidth
;
556 PRInt32 mSpansAllocated
, mSpansFreed
;
557 PRInt32 mFramesAllocated
, mFramesFreed
;
559 PLArenaPool mArena
; // Per span and per frame data, 4 byte aligned
565 nsresult
NewPerFrameData(PerFrameData
** aResult
);
567 nsresult
NewPerSpanData(PerSpanData
** aResult
);
569 void FreeSpan(PerSpanData
* psd
);
571 PRBool
InBlockContext() const {
572 return mSpanDepth
== 0;
575 void PushFrame(nsIFrame
* aFrame
);
577 void ApplyStartMargin(PerFrameData
* pfd
,
578 nsHTMLReflowState
& aReflowState
);
580 PRBool
CanPlaceFrame(PerFrameData
* pfd
,
581 PRUint8 aFrameDirection
,
582 PRBool aNotSafeToBreak
,
583 PRBool aFrameCanContinueTextRun
,
584 PRBool aCanRollBackBeforeFrame
,
585 nsHTMLReflowMetrics
& aMetrics
,
586 nsReflowStatus
& aStatus
,
587 PRBool
* aOptionalBreakAfterFits
);
589 void PlaceFrame(PerFrameData
* pfd
,
590 nsHTMLReflowMetrics
& aMetrics
);
592 void VerticalAlignFrames(PerSpanData
* psd
);
594 void PlaceTopBottomFrames(PerSpanData
* psd
,
595 nscoord aDistanceFromTop
,
596 nscoord aLineHeight
);
598 void RelativePositionFrames(PerSpanData
* psd
, nsOverflowAreas
& aOverflowAreas
);
600 PRBool
TrimTrailingWhiteSpaceIn(PerSpanData
* psd
, nscoord
* aDeltaWidth
);
602 void ComputeJustificationWeights(PerSpanData
* psd
, PRInt32
* numSpaces
, PRInt32
* numLetters
);
604 struct FrameJustificationState
{
605 PRInt32 mTotalNumSpaces
;
606 PRInt32 mTotalNumLetters
;
607 nscoord mTotalWidthForSpaces
;
608 nscoord mTotalWidthForLetters
;
609 PRInt32 mNumSpacesProcessed
;
610 PRInt32 mNumLettersProcessed
;
611 nscoord mWidthForSpacesProcessed
;
612 nscoord mWidthForLettersProcessed
;
615 // Apply justification. The return value is the amount by which the width of
616 // the span corresponding to aPSD got increased due to justification.
617 nscoord
ApplyFrameJustification(PerSpanData
* aPSD
,
618 FrameJustificationState
* aState
);
622 void DumpPerSpanData(PerSpanData
* psd
, PRInt32 aIndent
);
626 #endif /* nsLineLayout_h___ */