Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsLineLayout.h
blob5f895ebf5647d954460d0874efea00162ac8a56d
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"
22 #include "plarena.h"
23 #include "gfxTypes.h"
24 #include "WritingModes.h"
26 class nsFloatManager;
27 struct nsStyleText;
29 class nsLineLayout {
30 public:
31 nsLineLayout(nsPresContext* aPresContext,
32 nsFloatManager* aFloatManager,
33 const nsHTMLReflowState* aOuterReflowState,
34 const nsLineList::iterator* aLine);
35 ~nsLineLayout();
37 void Init(nsBlockReflowState* aState, nscoord aMinLineBSize,
38 int32_t aLineNumber) {
39 mBlockRS = aState;
40 mMinLineBSize = aMinLineBSize;
41 mLineNumber = aLineNumber;
44 int32_t GetLineNumber() const {
45 return mLineNumber;
48 void BeginLineReflow(nscoord aICoord, nscoord aBCoord,
49 nscoord aISize, nscoord aBSize,
50 bool aImpactedByFloats,
51 bool aIsTopOfPage,
52 mozilla::WritingMode aWritingMode,
53 nscoord aContainerWidth);
55 void EndLineReflow();
57 /**
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);
78 bool IsZeroBSize();
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,
85 bool& aPushedFrame);
87 void AddBulletFrame(nsIFrame* aFrame, const nsHTMLReflowMetrics& aMetrics);
89 void RemoveBulletFrame(nsIFrame* aFrame) {
90 PushFrame(aFrame);
93 /**
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
125 return mLineIsEmpty;
129 * @return true if so far during reflow no non-empty leaf content
130 * (non-collapsed whitespace, replaced element, inline-block, etc) has been
131 * placed in the line
133 bool LineAtStart() const
135 return mLineAtStart;
138 bool LineIsBreakable() const;
140 bool GetLineEndsInBR() const
142 return mLineEndsInBR;
145 void SetLineEndsInBR(bool aOn)
147 mLineEndsInBR = 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 {
181 return mInFirstLine;
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
223 * should break here
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() {
255 mNeedBackup = false;
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
321 * aAmount.
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();
333 protected:
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).
354 struct PerSpanData;
355 struct PerFrameData;
356 friend struct PerSpanData;
357 friend struct PerFrameData;
358 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
368 PerFrameData* mNext;
369 PerFrameData* mPrev;
371 // pointer to child span data if this is an inline container frame
372 PerSpanData* mSpan;
374 // The frame
375 nsIFrame* mFrame;
377 // From metrics
378 nscoord mAscent;
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
381 // writing mode
382 mozilla::LogicalRect mBounds;
383 nsOverflowAreas mOverflowAreas;
385 // From reflow-state
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
408 uint8_t mFlags;
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
415 mFlags |= aFlag;
417 else { // unset flag
418 mFlags &= ~aFlag;
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;
431 while (pfd->mNext) {
432 pfd = pfd->mNext;
434 return pfd;
437 PerFrameData* mFrameFreeList;
439 struct PerSpanData {
440 union {
441 PerSpanData* mParent;
442 PerSpanData* mNextFreeSpan;
444 PerFrameData* mFrame;
445 PerFrameData* mFirstFrame;
446 PerFrameData* mLastFrame;
448 const nsHTMLReflowState* mReflowState;
449 bool mNoWrap;
450 mozilla::WritingMode mWritingMode;
451 bool mZeroEffectiveSpanBox;
452 bool mContainsFloat;
453 bool mHasNonemptyContent;
455 nscoord mIStart;
456 nscoord mICoord;
457 nscoord mIEnd;
459 nscoord mBStartLeading, mBEndLeading;
460 nscoord mLogicalBSize;
461 nscoord mMinBCoord, mMaxBCoord;
462 nscoord* mBaseline;
464 void AppendFrame(PerFrameData* pfd) {
465 if (nullptr == mLastFrame) {
466 mFirstFrame = pfd;
468 else {
469 mLastFrame->mNext = pfd;
470 pfd->mPrev = mLastFrame;
472 mLastFrame = pfd;
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.
487 nscoord mTextIndent;
489 // This state varies during the reflow of a line but is line
490 // "global" state not span "local" state.
491 int32_t mLineNumber;
492 int32_t mTextJustificationNumSpaces;
493 int32_t mTextJustificationNumLetters;
495 int32_t mTotalPlacedFrames;
497 nscoord mBStartEdge;
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;
522 bool mHasBullet : 1;
523 bool mDirtyNextLine : 1;
524 bool mLineAtStart : 1;
526 int32_t mSpanDepth;
527 #ifdef DEBUG
528 int32_t mSpansAllocated, mSpansFreed;
529 int32_t mFramesAllocated, mFramesFreed;
530 #endif
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,
569 nscoord aLineBSize);
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);
594 #ifdef DEBUG
595 void DumpPerSpanData(PerSpanData* psd, int32_t aIndent);
596 #endif
599 #endif /* nsLineLayout_h___ */