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