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 /* representation of one line within a block frame, a CSS line box */ 8 9 #ifndef nsLineBox_h___ 10 #define nsLineBox_h___ 11 12 #include "mozilla/Attributes.h" 13 #include "mozilla/Likely.h" 14 15 #include "nsILineIterator.h" 16 #include "nsIFrame.h" 17 #include <algorithm> 18 19 class nsLineBox; 20 class nsFloatCache; 21 class nsFloatCacheList; 22 class nsFloatCacheFreeList; 23 class nsWindowSizes; 24 25 namespace mozilla { 26 class PresShell; 27 } // namespace mozilla 28 29 // State cached after reflowing a float. This state is used during 30 // incremental reflow when we avoid reflowing a float. 31 class nsFloatCache { 32 public: 33 nsFloatCache(); 34 #ifdef NS_BUILD_REFCNT_LOGGING 35 ~nsFloatCache(); 36 #else 37 ~nsFloatCache() = default; 38 #endif 39 Next()40 nsFloatCache* Next() const { return mNext; } 41 42 nsIFrame* mFloat; // floating frame 43 44 protected: 45 nsFloatCache* mNext; 46 47 friend class nsFloatCacheList; 48 friend class nsFloatCacheFreeList; 49 }; 50 51 //---------------------------------------- 52 53 class nsFloatCacheList { 54 public: 55 #ifdef NS_BUILD_REFCNT_LOGGING 56 nsFloatCacheList(); 57 #else 58 nsFloatCacheList() : mHead(nullptr) {} 59 #endif 60 ~nsFloatCacheList(); 61 IsEmpty()62 bool IsEmpty() const { return nullptr == mHead; } 63 NotEmpty()64 bool NotEmpty() const { return nullptr != mHead; } 65 Head()66 nsFloatCache* Head() const { return mHead; } 67 68 nsFloatCache* Tail() const; 69 70 void DeleteAll(); 71 72 nsFloatCache* Find(nsIFrame* aOutOfFlowFrame); 73 74 // Remove a nsFloatCache from this list. Deleting this nsFloatCache 75 // becomes the caller's responsibility. Remove(nsFloatCache * aElement)76 void Remove(nsFloatCache* aElement) { RemoveAndReturnPrev(aElement); } 77 78 // Steal away aList's nsFloatCache objects and put them in this 79 // list. aList must not be empty. 80 void Append(nsFloatCacheFreeList& aList); 81 82 protected: 83 nsFloatCache* mHead; 84 85 // Remove a nsFloatCache from this list. Deleting this nsFloatCache 86 // becomes the caller's responsibility. Returns the nsFloatCache that was 87 // before aElement, or nullptr if aElement was the first. 88 nsFloatCache* RemoveAndReturnPrev(nsFloatCache* aElement); 89 90 friend class nsFloatCacheFreeList; 91 }; 92 93 //--------------------------------------- 94 // Like nsFloatCacheList, but with fast access to the tail 95 96 class nsFloatCacheFreeList : private nsFloatCacheList { 97 public: 98 #ifdef NS_BUILD_REFCNT_LOGGING 99 nsFloatCacheFreeList(); 100 ~nsFloatCacheFreeList(); 101 #else 102 nsFloatCacheFreeList() : mTail(nullptr) {} 103 ~nsFloatCacheFreeList() = default; 104 #endif 105 106 // Reimplement trivial functions IsEmpty()107 bool IsEmpty() const { return nullptr == mHead; } 108 Head()109 nsFloatCache* Head() const { return mHead; } 110 Tail()111 nsFloatCache* Tail() const { return mTail; } 112 NotEmpty()113 bool NotEmpty() const { return nullptr != mHead; } 114 115 void DeleteAll(); 116 117 // Steal away aList's nsFloatCache objects and put them on this 118 // free-list. aList must not be empty. 119 void Append(nsFloatCacheList& aList); 120 121 void Append(nsFloatCache* aFloatCache); 122 123 void Remove(nsFloatCache* aElement); 124 125 // Remove an nsFloatCache object from this list and return it, or create 126 // a new one if this one is empty; Set its mFloat to aFloat. 127 nsFloatCache* Alloc(nsIFrame* aFloat); 128 129 protected: 130 nsFloatCache* mTail; 131 132 friend class nsFloatCacheList; 133 }; 134 135 //---------------------------------------------------------------------- 136 137 #define LINE_MAX_CHILD_COUNT INT32_MAX 138 139 /** 140 * Function to create a line box and initialize it with a single frame. 141 * The allocation is infallible. 142 * If the frame was moved from another line then you're responsible 143 * for notifying that line using NoteFrameRemoved(). Alternatively, 144 * it's better to use the next function that does that for you in an 145 * optimal way. 146 */ 147 nsLineBox* NS_NewLineBox(mozilla::PresShell* aPresShell, nsIFrame* aFrame, 148 bool aIsBlock); 149 /** 150 * Function to create a line box and initialize it with aCount frames 151 * that are currently on aFromLine. The allocation is infallible. 152 */ 153 nsLineBox* NS_NewLineBox(mozilla::PresShell* aPresShell, nsLineBox* aFromLine, 154 nsIFrame* aFrame, int32_t aCount); 155 156 class nsLineList; 157 158 // don't use the following names outside of this file. Instead, use 159 // nsLineList::iterator, etc. These are just here to allow them to 160 // be specified as parameters to methods of nsLineBox. 161 class nsLineList_iterator; 162 class nsLineList_const_iterator; 163 class nsLineList_reverse_iterator; 164 class nsLineList_const_reverse_iterator; 165 166 /** 167 * Users must have the class that is to be part of the list inherit 168 * from nsLineLink. If they want to be efficient, it should be the 169 * first base class. (This was originally nsCLink in a templatized 170 * nsCList, but it's still useful separately.) 171 */ 172 173 class nsLineLink { 174 public: 175 friend class nsLineList; 176 friend class nsLineList_iterator; 177 friend class nsLineList_reverse_iterator; 178 friend class nsLineList_const_iterator; 179 friend class nsLineList_const_reverse_iterator; 180 181 private: 182 nsLineLink* _mNext; // or head 183 nsLineLink* _mPrev; // or tail 184 }; 185 186 /** 187 * The nsLineBox class represents a horizontal line of frames. It contains 188 * enough state to support incremental reflow of the frames, event handling 189 * for the frames, and rendering of the frames. 190 */ 191 class nsLineBox final : public nsLineLink { 192 private: 193 nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock); 194 ~nsLineBox(); 195 196 // Infallible overloaded new operator. Uses an arena (which comes from the 197 // presShell) to perform the allocation. 198 void* operator new(size_t sz, mozilla::PresShell* aPresShell); 199 void operator delete(void* aPtr, size_t sz) = delete; 200 201 public: 202 // Use these functions to allocate and destroy line boxes 203 friend nsLineBox* NS_NewLineBox(mozilla::PresShell* aPresShell, 204 nsIFrame* aFrame, bool aIsBlock); 205 friend nsLineBox* NS_NewLineBox(mozilla::PresShell* aPresShell, 206 nsLineBox* aFromLine, nsIFrame* aFrame, 207 int32_t aCount); 208 void Destroy(mozilla::PresShell* aPresShell); 209 210 // mBlock bit IsBlock()211 bool IsBlock() const { return mFlags.mBlock; } IsInline()212 bool IsInline() const { return !mFlags.mBlock; } 213 214 // mDirty bit MarkDirty()215 void MarkDirty() { mFlags.mDirty = 1; } ClearDirty()216 void ClearDirty() { mFlags.mDirty = 0; } IsDirty()217 bool IsDirty() const { return mFlags.mDirty; } 218 219 // mPreviousMarginDirty bit MarkPreviousMarginDirty()220 void MarkPreviousMarginDirty() { mFlags.mPreviousMarginDirty = 1; } ClearPreviousMarginDirty()221 void ClearPreviousMarginDirty() { mFlags.mPreviousMarginDirty = 0; } IsPreviousMarginDirty()222 bool IsPreviousMarginDirty() const { return mFlags.mPreviousMarginDirty; } 223 224 // mHasClearance bit SetHasClearance()225 void SetHasClearance() { mFlags.mHasClearance = 1; } ClearHasClearance()226 void ClearHasClearance() { mFlags.mHasClearance = 0; } HasClearance()227 bool HasClearance() const { return mFlags.mHasClearance; } 228 229 // mImpactedByFloat bit SetLineIsImpactedByFloat(bool aValue)230 void SetLineIsImpactedByFloat(bool aValue) { 231 mFlags.mImpactedByFloat = aValue; 232 } IsImpactedByFloat()233 bool IsImpactedByFloat() const { return mFlags.mImpactedByFloat; } 234 235 // mLineWrapped bit SetLineWrapped(bool aOn)236 void SetLineWrapped(bool aOn) { mFlags.mLineWrapped = aOn; } IsLineWrapped()237 bool IsLineWrapped() const { return mFlags.mLineWrapped; } 238 239 // mInvalidateTextRuns bit SetInvalidateTextRuns(bool aOn)240 void SetInvalidateTextRuns(bool aOn) { mFlags.mInvalidateTextRuns = aOn; } GetInvalidateTextRuns()241 bool GetInvalidateTextRuns() const { return mFlags.mInvalidateTextRuns; } 242 243 // mResizeReflowOptimizationDisabled bit DisableResizeReflowOptimization()244 void DisableResizeReflowOptimization() { 245 mFlags.mResizeReflowOptimizationDisabled = true; 246 } EnableResizeReflowOptimization()247 void EnableResizeReflowOptimization() { 248 mFlags.mResizeReflowOptimizationDisabled = false; 249 } ResizeReflowOptimizationDisabled()250 bool ResizeReflowOptimizationDisabled() const { 251 return mFlags.mResizeReflowOptimizationDisabled; 252 } 253 254 // mHasMarker bit SetHasMarker()255 void SetHasMarker() { 256 mFlags.mHasMarker = true; 257 InvalidateCachedIsEmpty(); 258 } ClearHasMarker()259 void ClearHasMarker() { 260 mFlags.mHasMarker = false; 261 InvalidateCachedIsEmpty(); 262 } HasMarker()263 bool HasMarker() const { return mFlags.mHasMarker; } 264 265 // mHadFloatPushed bit SetHadFloatPushed()266 void SetHadFloatPushed() { mFlags.mHadFloatPushed = true; } ClearHadFloatPushed()267 void ClearHadFloatPushed() { mFlags.mHadFloatPushed = false; } HadFloatPushed()268 bool HadFloatPushed() const { return mFlags.mHadFloatPushed; } 269 270 // mHasLineClampEllipsis bit SetHasLineClampEllipsis()271 void SetHasLineClampEllipsis() { mFlags.mHasLineClampEllipsis = true; } ClearHasLineClampEllipsis()272 void ClearHasLineClampEllipsis() { mFlags.mHasLineClampEllipsis = false; } HasLineClampEllipsis()273 bool HasLineClampEllipsis() const { return mFlags.mHasLineClampEllipsis; } 274 275 // mMovedFragments bit SetMovedFragments()276 void SetMovedFragments() { mFlags.mMovedFragments = true; } ClearMovedFragments()277 void ClearMovedFragments() { mFlags.mMovedFragments = false; } MovedFragments()278 bool MovedFragments() const { return mFlags.mMovedFragments; } 279 280 private: 281 // Add a hash table for fast lookup when the line has more frames than this. 282 static const uint32_t kMinChildCountForHashtable = 200; 283 284 /** 285 * Take ownership of aFromLine's hash table and remove the frames that 286 * stay on aFromLine from it, i.e. aFromLineNewCount frames starting with 287 * mFirstChild. This method is used to optimize moving a large number 288 * of frames from one line to the next. 289 */ 290 void StealHashTableFrom(nsLineBox* aFromLine, uint32_t aFromLineNewCount); 291 292 /** 293 * Does the equivalent of this->NoteFrameAdded and aFromLine->NoteFrameRemoved 294 * for each frame on this line, but in a optimized way. 295 */ 296 void NoteFramesMovedFrom(nsLineBox* aFromLine); 297 SwitchToHashtable()298 void SwitchToHashtable() { 299 MOZ_ASSERT(!mFlags.mHasHashedFrames); 300 uint32_t count = GetChildCount(); 301 mFlags.mHasHashedFrames = 1; 302 uint32_t minLength = 303 std::max(kMinChildCountForHashtable, 304 uint32_t(PLDHashTable::kDefaultInitialLength)); 305 mFrames = 306 new nsTHashtable<nsPtrHashKey<nsIFrame> >(std::max(count, minLength)); 307 for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) { 308 mFrames->PutEntry(f); 309 } 310 } SwitchToCounter()311 void SwitchToCounter() { 312 MOZ_ASSERT(mFlags.mHasHashedFrames); 313 uint32_t count = GetChildCount(); 314 delete mFrames; 315 mFlags.mHasHashedFrames = 0; 316 mChildCount = count; 317 } 318 319 public: GetChildCount()320 int32_t GetChildCount() const { 321 return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() 322 : mChildCount; 323 } 324 325 /** 326 * Register that aFrame is now on this line. 327 */ NoteFrameAdded(nsIFrame * aFrame)328 void NoteFrameAdded(nsIFrame* aFrame) { 329 if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { 330 mFrames->PutEntry(aFrame); 331 } else { 332 if (++mChildCount >= kMinChildCountForHashtable) { 333 SwitchToHashtable(); 334 } 335 } 336 } 337 338 /** 339 * Register that aFrame is not on this line anymore. 340 */ NoteFrameRemoved(nsIFrame * aFrame)341 void NoteFrameRemoved(nsIFrame* aFrame) { 342 MOZ_ASSERT(GetChildCount() > 0); 343 if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { 344 mFrames->RemoveEntry(aFrame); 345 if (mFrames->Count() < kMinChildCountForHashtable) { 346 SwitchToCounter(); 347 } 348 } else { 349 --mChildCount; 350 } 351 } 352 353 // mBreakType value 354 // Break information is applied *before* the line if the line is a block, 355 // or *after* the line if the line is an inline. Confusing, I know, but 356 // using different names should help. 357 using StyleClear = mozilla::StyleClear; HasBreakBefore()358 bool HasBreakBefore() const { 359 return IsBlock() && StyleClear::None != BreakType(); 360 } SetBreakTypeBefore(StyleClear aBreakType)361 void SetBreakTypeBefore(StyleClear aBreakType) { 362 MOZ_ASSERT(IsBlock(), "Only blocks have break-before"); 363 MOZ_ASSERT( 364 aBreakType == StyleClear::None || aBreakType == StyleClear::Left || 365 aBreakType == StyleClear::Right || aBreakType == StyleClear::Both, 366 "Only float break types are allowed before a line"); 367 mFlags.mBreakType = aBreakType; 368 } GetBreakTypeBefore()369 StyleClear GetBreakTypeBefore() const { 370 return IsBlock() ? BreakType() : StyleClear::None; 371 } 372 HasBreakAfter()373 bool HasBreakAfter() const { 374 return !IsBlock() && StyleClear::None != BreakType(); 375 } SetBreakTypeAfter(StyleClear aBreakType)376 void SetBreakTypeAfter(StyleClear aBreakType) { 377 MOZ_ASSERT(!IsBlock(), "Only inlines have break-after"); 378 mFlags.mBreakType = aBreakType; 379 } HasFloatBreakAfter()380 bool HasFloatBreakAfter() const { 381 return !IsBlock() && (StyleClear::Left == BreakType() || 382 StyleClear::Right == BreakType() || 383 StyleClear::Both == BreakType()); 384 } GetBreakTypeAfter()385 StyleClear GetBreakTypeAfter() const { 386 return !IsBlock() ? BreakType() : StyleClear::None; 387 } 388 389 // mCarriedOutBEndMargin value 390 nsCollapsingMargin GetCarriedOutBEndMargin() const; 391 // Returns true if the margin changed 392 bool SetCarriedOutBEndMargin(nsCollapsingMargin aValue); 393 394 // mFloats HasFloats()395 bool HasFloats() const { 396 return (IsInline() && mInlineData) && mInlineData->mFloats.NotEmpty(); 397 } 398 nsFloatCache* GetFirstFloat(); 399 void FreeFloats(nsFloatCacheFreeList& aFreeList); 400 void AppendFloats(nsFloatCacheFreeList& aFreeList); 401 bool RemoveFloat(nsIFrame* aFrame); 402 403 // Combined area is the area of the line that should influence the 404 // overflow area of its parent block. The combined area should be 405 // used for painting-related things, but should never be used for 406 // layout (except for handling of 'overflow'). 407 void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas); GetOverflowArea(nsOverflowType aType,mozilla::WritingMode aWM,const nsSize & aContainerSize)408 mozilla::LogicalRect GetOverflowArea(nsOverflowType aType, 409 mozilla::WritingMode aWM, 410 const nsSize& aContainerSize) { 411 return mozilla::LogicalRect(aWM, GetOverflowArea(aType), aContainerSize); 412 } GetOverflowArea(nsOverflowType aType)413 nsRect GetOverflowArea(nsOverflowType aType) const { 414 return mData ? mData->mOverflowAreas.Overflow(aType) : GetPhysicalBounds(); 415 } GetOverflowAreas()416 nsOverflowAreas GetOverflowAreas() const { 417 if (mData) { 418 return mData->mOverflowAreas; 419 } 420 nsRect bounds = GetPhysicalBounds(); 421 return nsOverflowAreas(bounds, bounds); 422 } GetVisualOverflowArea()423 nsRect GetVisualOverflowArea() const { 424 return GetOverflowArea(eVisualOverflow); 425 } GetScrollableOverflowArea()426 nsRect GetScrollableOverflowArea() { 427 return GetOverflowArea(eScrollableOverflow); 428 } 429 SlideBy(nscoord aDBCoord,const nsSize & aContainerSize)430 void SlideBy(nscoord aDBCoord, const nsSize& aContainerSize) { 431 NS_ASSERTION( 432 aContainerSize == mContainerSize || mContainerSize == nsSize(-1, -1), 433 "container size doesn't match"); 434 mContainerSize = aContainerSize; 435 mBounds.BStart(mWritingMode) += aDBCoord; 436 if (mData) { 437 // Use a null containerSize to convert vector from logical to physical. 438 const nsSize nullContainerSize; 439 nsPoint physicalDelta = 440 mozilla::LogicalPoint(mWritingMode, 0, aDBCoord) 441 .GetPhysicalPoint(mWritingMode, nullContainerSize); 442 NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 443 mData->mOverflowAreas.Overflow(otype) += physicalDelta; 444 } 445 } 446 } 447 448 // Container-size for the line is changing (and therefore if writing mode 449 // was vertical-rl, the line will move physically; this is like SlideBy, 450 // but it is the container size instead of the line's own logical coord 451 // that is changing. UpdateContainerSize(const nsSize aNewContainerSize)452 nsSize UpdateContainerSize(const nsSize aNewContainerSize) { 453 NS_ASSERTION(mContainerSize != nsSize(-1, -1), "container size not set"); 454 nsSize delta = mContainerSize - aNewContainerSize; 455 mContainerSize = aNewContainerSize; 456 // this has a physical-coordinate effect only in vertical-rl mode 457 if (mWritingMode.IsVerticalRL() && mData) { 458 nsPoint physicalDelta(-delta.width, 0); 459 NS_FOR_FRAME_OVERFLOW_TYPES(otype) { 460 mData->mOverflowAreas.Overflow(otype) += physicalDelta; 461 } 462 } 463 return delta; 464 } 465 IndentBy(nscoord aDICoord,const nsSize & aContainerSize)466 void IndentBy(nscoord aDICoord, const nsSize& aContainerSize) { 467 NS_ASSERTION( 468 aContainerSize == mContainerSize || mContainerSize == nsSize(-1, -1), 469 "container size doesn't match"); 470 mContainerSize = aContainerSize; 471 mBounds.IStart(mWritingMode) += aDICoord; 472 } 473 ExpandBy(nscoord aDISize,const nsSize & aContainerSize)474 void ExpandBy(nscoord aDISize, const nsSize& aContainerSize) { 475 NS_ASSERTION( 476 aContainerSize == mContainerSize || mContainerSize == nsSize(-1, -1), 477 "container size doesn't match"); 478 mContainerSize = aContainerSize; 479 mBounds.ISize(mWritingMode) += aDISize; 480 } 481 482 /** 483 * The logical ascent (distance from block-start to baseline) of the 484 * linebox is the logical ascent of the anonymous inline box (for 485 * which we don't actually create a frame) that wraps all the 486 * consecutive inline children of a block. 487 * 488 * This is currently unused for block lines. 489 */ GetLogicalAscent()490 nscoord GetLogicalAscent() const { return mAscent; } SetLogicalAscent(nscoord aAscent)491 void SetLogicalAscent(nscoord aAscent) { mAscent = aAscent; } 492 BStart()493 nscoord BStart() const { return mBounds.BStart(mWritingMode); } BSize()494 nscoord BSize() const { return mBounds.BSize(mWritingMode); } BEnd()495 nscoord BEnd() const { return mBounds.BEnd(mWritingMode); } IStart()496 nscoord IStart() const { return mBounds.IStart(mWritingMode); } ISize()497 nscoord ISize() const { return mBounds.ISize(mWritingMode); } IEnd()498 nscoord IEnd() const { return mBounds.IEnd(mWritingMode); } SetBoundsEmpty()499 void SetBoundsEmpty() { 500 mBounds.IStart(mWritingMode) = 0; 501 mBounds.ISize(mWritingMode) = 0; 502 mBounds.BStart(mWritingMode) = 0; 503 mBounds.BSize(mWritingMode) = 0; 504 } 505 506 using PostDestroyData = nsIFrame::PostDestroyData; 507 static void DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines, 508 nsIFrame* aDestructRoot, nsFrameList* aFrames, 509 PostDestroyData& aPostDestroyData); 510 511 // search from end to beginning of [aBegin, aEnd) 512 // Returns true if it found the line and false if not. 513 // Moves aEnd as it searches so that aEnd points to the resulting line. 514 // aLastFrameBeforeEnd is the last frame before aEnd (so if aEnd is 515 // the end of the line list, it's just the last frame in the frame 516 // list). 517 static bool RFindLineContaining(nsIFrame* aFrame, 518 const nsLineList_iterator& aBegin, 519 nsLineList_iterator& aEnd, 520 nsIFrame* aLastFrameBeforeEnd, 521 int32_t* aFrameIndexInLine); 522 523 #ifdef DEBUG_FRAME_DUMP 524 static const char* BreakTypeToString(StyleClear aBreakType); 525 char* StateToString(char* aBuf, int32_t aBufSize) const; 526 527 void List(FILE* out, int32_t aIndent, 528 nsIFrame::ListFlags aFlags = nsIFrame::ListFlags()) const; 529 void List(FILE* out = stderr, const char* aPrefix = "", 530 nsIFrame::ListFlags aFlags = nsIFrame::ListFlags()) const; 531 nsIFrame* LastChild() const; 532 #endif 533 534 void AddSizeOfExcludingThis(nsWindowSizes& aSizes) const; 535 536 // Find the index of aFrame within the line, starting search at the start. 537 int32_t IndexOf(nsIFrame* aFrame) const; 538 539 // Find the index of aFrame within the line, starting search at the end. 540 // (Produces the same result as IndexOf, but with different performance 541 // characteristics.) The caller must provide the last frame in the line. 542 int32_t RIndexOf(nsIFrame* aFrame, nsIFrame* aLastFrameInLine) const; 543 Contains(nsIFrame * aFrame)544 bool Contains(nsIFrame* aFrame) const { 545 return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame) 546 : IndexOf(aFrame) >= 0; 547 } 548 549 // whether the line box is "logically" empty (just like nsIFrame::IsEmpty) 550 bool IsEmpty() const; 551 552 // Call this only while in Reflow() for the block the line belongs 553 // to, only between reflowing the line (or sliding it, if we skip 554 // reflowing it) and the end of reflowing the block. 555 bool CachedIsEmpty(); 556 InvalidateCachedIsEmpty()557 void InvalidateCachedIsEmpty() { mFlags.mEmptyCacheValid = false; } 558 559 // For debugging purposes IsValidCachedIsEmpty()560 bool IsValidCachedIsEmpty() { return mFlags.mEmptyCacheValid; } 561 562 #ifdef DEBUG 563 static int32_t GetCtorCount(); 564 #endif 565 566 nsIFrame* mFirstChild; 567 568 mozilla::WritingMode mWritingMode; 569 570 // Physical size. Use only for physical <-> logical coordinate conversion. 571 nsSize mContainerSize; 572 573 private: 574 mozilla::LogicalRect mBounds; 575 576 public: GetBounds()577 const mozilla::LogicalRect& GetBounds() { return mBounds; } GetPhysicalBounds()578 nsRect GetPhysicalBounds() const { 579 if (mBounds.IsAllZero()) { 580 return nsRect(0, 0, 0, 0); 581 } 582 583 NS_ASSERTION(mContainerSize != nsSize(-1, -1), 584 "mContainerSize not initialized"); 585 return mBounds.GetPhysicalRect(mWritingMode, mContainerSize); 586 } SetBounds(mozilla::WritingMode aWritingMode,nscoord aIStart,nscoord aBStart,nscoord aISize,nscoord aBSize,const nsSize & aContainerSize)587 void SetBounds(mozilla::WritingMode aWritingMode, nscoord aIStart, 588 nscoord aBStart, nscoord aISize, nscoord aBSize, 589 const nsSize& aContainerSize) { 590 mWritingMode = aWritingMode; 591 mContainerSize = aContainerSize; 592 mBounds = 593 mozilla::LogicalRect(aWritingMode, aIStart, aBStart, aISize, aBSize); 594 } SetBounds(mozilla::WritingMode aWritingMode,nsRect aRect,const nsSize & aContainerSize)595 void SetBounds(mozilla::WritingMode aWritingMode, nsRect aRect, 596 const nsSize& aContainerSize) { 597 mWritingMode = aWritingMode; 598 mContainerSize = aContainerSize; 599 mBounds = mozilla::LogicalRect(aWritingMode, aRect, aContainerSize); 600 } 601 602 // mFlags.mHasHashedFrames says which one to use 603 union { 604 nsTHashtable<nsPtrHashKey<nsIFrame> >* mFrames; 605 uint32_t mChildCount; 606 }; 607 608 struct FlagBits { 609 bool mDirty : 1; 610 bool mPreviousMarginDirty : 1; 611 bool mHasClearance : 1; 612 bool mBlock : 1; 613 bool mImpactedByFloat : 1; 614 bool mLineWrapped : 1; 615 bool mInvalidateTextRuns : 1; 616 // default 0 = means that the opt potentially applies to this line. 617 // 1 = never skip reflowing this line for a resize reflow 618 bool mResizeReflowOptimizationDisabled : 1; 619 bool mEmptyCacheValid : 1; 620 bool mEmptyCacheState : 1; 621 // mHasMarker indicates that this is an inline line whose block's 622 // ::marker is adjacent to this line and non-empty. 623 bool mHasMarker : 1; 624 // Indicates that this line *may* have a placeholder for a float 625 // that was pushed to a later column or page. 626 bool mHadFloatPushed : 1; 627 bool mHasHashedFrames : 1; 628 // Indicates that this line is the one identified by an ancestor block 629 // with -webkit-line-clamp on its legacy flex container, and that subsequent 630 // lines under that block are "clamped" away, and therefore we need to 631 // render a 'text-overflow: ellipsis'-like marker in this line. At most one 632 // line in the set of lines found by LineClampLineIterator for a given 633 // block will have this flag set. 634 bool mHasLineClampEllipsis : 1; 635 // Has this line moved to a different fragment of the block since 636 // the last time it was reflowed? 637 bool mMovedFragments : 1; 638 StyleClear mBreakType; 639 }; 640 641 struct ExtraData { ExtraDataExtraData642 explicit ExtraData(const nsRect& aBounds) 643 : mOverflowAreas(aBounds, aBounds) {} 644 nsOverflowAreas mOverflowAreas; 645 }; 646 647 struct ExtraBlockData : public ExtraData { ExtraBlockDataExtraBlockData648 explicit ExtraBlockData(const nsRect& aBounds) 649 : ExtraData(aBounds), mCarriedOutBEndMargin() {} 650 nsCollapsingMargin mCarriedOutBEndMargin; 651 }; 652 653 struct ExtraInlineData : public ExtraData { ExtraInlineDataExtraInlineData654 explicit ExtraInlineData(const nsRect& aBounds) 655 : ExtraData(aBounds), 656 mFloatEdgeIStart(nscoord_MIN), 657 mFloatEdgeIEnd(nscoord_MIN) {} 658 nscoord mFloatEdgeIStart; 659 nscoord mFloatEdgeIEnd; 660 nsFloatCacheList mFloats; 661 }; 662 GetFloatEdges(nscoord * aStart,nscoord * aEnd)663 bool GetFloatEdges(nscoord* aStart, nscoord* aEnd) const { 664 MOZ_ASSERT(IsInline(), "block line can't have float edges"); 665 if (mInlineData && mInlineData->mFloatEdgeIStart != nscoord_MIN) { 666 *aStart = mInlineData->mFloatEdgeIStart; 667 *aEnd = mInlineData->mFloatEdgeIEnd; 668 return true; 669 } 670 return false; 671 } 672 void SetFloatEdges(nscoord aStart, nscoord aEnd); 673 void ClearFloatEdges(); 674 675 protected: 676 nscoord mAscent; // see |SetAscent| / |GetAscent| 677 static_assert(sizeof(FlagBits) <= sizeof(uint32_t), 678 "size of FlagBits should not be larger than size of uint32_t"); 679 union { 680 uint32_t mAllFlags; 681 FlagBits mFlags; 682 }; 683 BreakType()684 StyleClear BreakType() const { return mFlags.mBreakType; }; 685 686 union { 687 ExtraData* mData; 688 ExtraBlockData* mBlockData; 689 ExtraInlineData* mInlineData; 690 }; 691 692 void Cleanup(); 693 void MaybeFreeData(); 694 }; 695 696 /** 697 * A linked list type where the items in the list must inherit from 698 * a link type to fuse allocations. 699 * 700 * API heavily based on the |list| class in the C++ standard. 701 */ 702 703 class nsLineList_iterator { 704 public: 705 friend class nsLineList; 706 friend class nsLineList_reverse_iterator; 707 friend class nsLineList_const_iterator; 708 friend class nsLineList_const_reverse_iterator; 709 710 typedef nsLineList_iterator iterator_self_type; 711 typedef nsLineList_reverse_iterator iterator_reverse_type; 712 713 typedef nsLineBox& reference; 714 typedef const nsLineBox& const_reference; 715 716 typedef nsLineBox* pointer; 717 typedef const nsLineBox* const_pointer; 718 719 typedef uint32_t size_type; 720 typedef int32_t difference_type; 721 722 typedef nsLineLink link_type; 723 724 #ifdef DEBUG nsLineList_iterator()725 nsLineList_iterator() : mListLink(nullptr) { 726 memset(&mCurrent, 0xcd, sizeof(mCurrent)); 727 } 728 #else 729 // Auto generated default constructor OK. 730 #endif 731 // Auto generated copy-constructor OK. 732 733 inline iterator_self_type& operator=(const iterator_self_type& aOther); 734 inline iterator_self_type& operator=(const iterator_reverse_type& aOther); 735 736 iterator_self_type& operator++() { 737 mCurrent = mCurrent->_mNext; 738 return *this; 739 } 740 741 iterator_self_type operator++(int) { 742 iterator_self_type rv(*this); 743 mCurrent = mCurrent->_mNext; 744 return rv; 745 } 746 747 iterator_self_type& operator--() { 748 mCurrent = mCurrent->_mPrev; 749 return *this; 750 } 751 752 iterator_self_type operator--(int) { 753 iterator_self_type rv(*this); 754 mCurrent = mCurrent->_mPrev; 755 return rv; 756 } 757 758 reference operator*() { 759 MOZ_ASSERT(mListLink); 760 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 761 return *static_cast<pointer>(mCurrent); 762 } 763 764 pointer operator->() { 765 MOZ_ASSERT(mListLink); 766 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 767 return static_cast<pointer>(mCurrent); 768 } 769 get()770 pointer get() { 771 MOZ_ASSERT(mListLink); 772 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 773 return static_cast<pointer>(mCurrent); 774 } 775 pointer()776 operator pointer() { 777 MOZ_ASSERT(mListLink); 778 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 779 return static_cast<pointer>(mCurrent); 780 } 781 782 const_reference operator*() const { 783 MOZ_ASSERT(mListLink); 784 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 785 return *static_cast<const_pointer>(mCurrent); 786 } 787 788 const_pointer operator->() const { 789 MOZ_ASSERT(mListLink); 790 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 791 return static_cast<const_pointer>(mCurrent); 792 } 793 794 #ifndef __MWERKS__ const_pointer()795 operator const_pointer() const { 796 MOZ_ASSERT(mListLink); 797 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 798 return static_cast<const_pointer>(mCurrent); 799 } 800 #endif /* !__MWERKS__ */ 801 next()802 iterator_self_type next() { 803 iterator_self_type copy(*this); 804 return ++copy; 805 } 806 next()807 const iterator_self_type next() const { 808 iterator_self_type copy(*this); 809 return ++copy; 810 } 811 prev()812 iterator_self_type prev() { 813 iterator_self_type copy(*this); 814 return --copy; 815 } 816 prev()817 const iterator_self_type prev() const { 818 iterator_self_type copy(*this); 819 return --copy; 820 } 821 822 // Passing by value rather than by reference and reference to const 823 // to keep AIX happy. 824 bool operator==(const iterator_self_type aOther) const { 825 MOZ_ASSERT(mListLink); 826 MOZ_ASSERT(mListLink == aOther.mListLink, 827 "comparing iterators over different lists"); 828 return mCurrent == aOther.mCurrent; 829 } 830 bool operator!=(const iterator_self_type aOther) const { 831 MOZ_ASSERT(mListLink); 832 MOZ_ASSERT(mListLink == aOther.mListLink, 833 "comparing iterators over different lists"); 834 return mCurrent != aOther.mCurrent; 835 } 836 bool operator==(const iterator_self_type aOther) { 837 MOZ_ASSERT(mListLink); 838 MOZ_ASSERT(mListLink == aOther.mListLink, 839 "comparing iterators over different lists"); 840 return mCurrent == aOther.mCurrent; 841 } 842 bool operator!=(const iterator_self_type aOther) { 843 MOZ_ASSERT(mListLink); 844 MOZ_ASSERT(mListLink == aOther.mListLink, 845 "comparing iterators over different lists"); 846 return mCurrent != aOther.mCurrent; 847 } 848 849 #ifdef DEBUG IsInSameList(const iterator_self_type aOther)850 bool IsInSameList(const iterator_self_type aOther) const { 851 return mListLink == aOther.mListLink; 852 } 853 #endif 854 855 private: 856 link_type* mCurrent; 857 #ifdef DEBUG 858 link_type* mListLink; // the list's link, i.e., the end 859 #endif 860 }; 861 862 class nsLineList_reverse_iterator { 863 public: 864 friend class nsLineList; 865 friend class nsLineList_iterator; 866 friend class nsLineList_const_iterator; 867 friend class nsLineList_const_reverse_iterator; 868 869 typedef nsLineList_reverse_iterator iterator_self_type; 870 typedef nsLineList_iterator iterator_reverse_type; 871 872 typedef nsLineBox& reference; 873 typedef const nsLineBox& const_reference; 874 875 typedef nsLineBox* pointer; 876 typedef const nsLineBox* const_pointer; 877 878 typedef uint32_t size_type; 879 typedef int32_t difference_type; 880 881 typedef nsLineLink link_type; 882 883 #ifdef DEBUG nsLineList_reverse_iterator()884 nsLineList_reverse_iterator() : mListLink(nullptr) { 885 memset(&mCurrent, 0xcd, sizeof(mCurrent)); 886 } 887 #else 888 // Auto generated default constructor OK. 889 #endif 890 // Auto generated copy-constructor OK. 891 892 inline iterator_self_type& operator=(const iterator_reverse_type& aOther); 893 inline iterator_self_type& operator=(const iterator_self_type& aOther); 894 895 iterator_self_type& operator++() { 896 mCurrent = mCurrent->_mPrev; 897 return *this; 898 } 899 900 iterator_self_type operator++(int) { 901 iterator_self_type rv(*this); 902 mCurrent = mCurrent->_mPrev; 903 return rv; 904 } 905 906 iterator_self_type& operator--() { 907 mCurrent = mCurrent->_mNext; 908 return *this; 909 } 910 911 iterator_self_type operator--(int) { 912 iterator_self_type rv(*this); 913 mCurrent = mCurrent->_mNext; 914 return rv; 915 } 916 917 reference operator*() { 918 MOZ_ASSERT(mListLink); 919 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 920 return *static_cast<pointer>(mCurrent); 921 } 922 923 pointer operator->() { 924 MOZ_ASSERT(mListLink); 925 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 926 return static_cast<pointer>(mCurrent); 927 } 928 get()929 pointer get() { 930 MOZ_ASSERT(mListLink); 931 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 932 return static_cast<pointer>(mCurrent); 933 } 934 pointer()935 operator pointer() { 936 MOZ_ASSERT(mListLink); 937 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 938 return static_cast<pointer>(mCurrent); 939 } 940 941 const_reference operator*() const { 942 MOZ_ASSERT(mListLink); 943 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 944 return *static_cast<const_pointer>(mCurrent); 945 } 946 947 const_pointer operator->() const { 948 MOZ_ASSERT(mListLink); 949 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 950 return static_cast<const_pointer>(mCurrent); 951 } 952 953 #ifndef __MWERKS__ const_pointer()954 operator const_pointer() const { 955 MOZ_ASSERT(mListLink); 956 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 957 return static_cast<const_pointer>(mCurrent); 958 } 959 #endif /* !__MWERKS__ */ 960 961 // Passing by value rather than by reference and reference to const 962 // to keep AIX happy. 963 bool operator==(const iterator_self_type aOther) const { 964 MOZ_ASSERT(mListLink); 965 NS_ASSERTION(mListLink == aOther.mListLink, 966 "comparing iterators over different lists"); 967 return mCurrent == aOther.mCurrent; 968 } 969 bool operator!=(const iterator_self_type aOther) const { 970 MOZ_ASSERT(mListLink); 971 NS_ASSERTION(mListLink == aOther.mListLink, 972 "comparing iterators over different lists"); 973 return mCurrent != aOther.mCurrent; 974 } 975 bool operator==(const iterator_self_type aOther) { 976 MOZ_ASSERT(mListLink); 977 NS_ASSERTION(mListLink == aOther.mListLink, 978 "comparing iterators over different lists"); 979 return mCurrent == aOther.mCurrent; 980 } 981 bool operator!=(const iterator_self_type aOther) { 982 MOZ_ASSERT(mListLink); 983 NS_ASSERTION(mListLink == aOther.mListLink, 984 "comparing iterators over different lists"); 985 return mCurrent != aOther.mCurrent; 986 } 987 988 #ifdef DEBUG IsInSameList(const iterator_self_type aOther)989 bool IsInSameList(const iterator_self_type aOther) const { 990 return mListLink == aOther.mListLink; 991 } 992 #endif 993 994 private: 995 link_type* mCurrent; 996 #ifdef DEBUG 997 link_type* mListLink; // the list's link, i.e., the end 998 #endif 999 }; 1000 1001 class nsLineList_const_iterator { 1002 public: 1003 friend class nsLineList; 1004 friend class nsLineList_iterator; 1005 friend class nsLineList_reverse_iterator; 1006 friend class nsLineList_const_reverse_iterator; 1007 1008 typedef nsLineList_const_iterator iterator_self_type; 1009 typedef nsLineList_const_reverse_iterator iterator_reverse_type; 1010 typedef nsLineList_iterator iterator_nonconst_type; 1011 typedef nsLineList_reverse_iterator iterator_nonconst_reverse_type; 1012 1013 typedef nsLineBox& reference; 1014 typedef const nsLineBox& const_reference; 1015 1016 typedef nsLineBox* pointer; 1017 typedef const nsLineBox* const_pointer; 1018 1019 typedef uint32_t size_type; 1020 typedef int32_t difference_type; 1021 1022 typedef nsLineLink link_type; 1023 1024 #ifdef DEBUG nsLineList_const_iterator()1025 nsLineList_const_iterator() : mListLink(nullptr) { 1026 memset(&mCurrent, 0xcd, sizeof(mCurrent)); 1027 } 1028 #else 1029 // Auto generated default constructor OK. 1030 #endif 1031 // Auto generated copy-constructor OK. 1032 1033 inline iterator_self_type& operator=(const iterator_nonconst_type& aOther); 1034 inline iterator_self_type& operator=( 1035 const iterator_nonconst_reverse_type& aOther); 1036 inline iterator_self_type& operator=(const iterator_self_type& aOther); 1037 inline iterator_self_type& operator=(const iterator_reverse_type& aOther); 1038 1039 iterator_self_type& operator++() { 1040 mCurrent = mCurrent->_mNext; 1041 return *this; 1042 } 1043 1044 iterator_self_type operator++(int) { 1045 iterator_self_type rv(*this); 1046 mCurrent = mCurrent->_mNext; 1047 return rv; 1048 } 1049 1050 iterator_self_type& operator--() { 1051 mCurrent = mCurrent->_mPrev; 1052 return *this; 1053 } 1054 1055 iterator_self_type operator--(int) { 1056 iterator_self_type rv(*this); 1057 mCurrent = mCurrent->_mPrev; 1058 return rv; 1059 } 1060 1061 const_reference operator*() const { 1062 MOZ_ASSERT(mListLink); 1063 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1064 return *static_cast<const_pointer>(mCurrent); 1065 } 1066 1067 const_pointer operator->() const { 1068 MOZ_ASSERT(mListLink); 1069 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1070 return static_cast<const_pointer>(mCurrent); 1071 } 1072 get()1073 const_pointer get() const { 1074 MOZ_ASSERT(mListLink); 1075 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1076 return static_cast<const_pointer>(mCurrent); 1077 } 1078 1079 #ifndef __MWERKS__ const_pointer()1080 operator const_pointer() const { 1081 MOZ_ASSERT(mListLink); 1082 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1083 return static_cast<const_pointer>(mCurrent); 1084 } 1085 #endif /* !__MWERKS__ */ 1086 next()1087 const iterator_self_type next() const { 1088 iterator_self_type copy(*this); 1089 return ++copy; 1090 } 1091 prev()1092 const iterator_self_type prev() const { 1093 iterator_self_type copy(*this); 1094 return --copy; 1095 } 1096 1097 // Passing by value rather than by reference and reference to const 1098 // to keep AIX happy. 1099 bool operator==(const iterator_self_type aOther) const { 1100 MOZ_ASSERT(mListLink); 1101 NS_ASSERTION(mListLink == aOther.mListLink, 1102 "comparing iterators over different lists"); 1103 return mCurrent == aOther.mCurrent; 1104 } 1105 bool operator!=(const iterator_self_type aOther) const { 1106 MOZ_ASSERT(mListLink); 1107 NS_ASSERTION(mListLink == aOther.mListLink, 1108 "comparing iterators over different lists"); 1109 return mCurrent != aOther.mCurrent; 1110 } 1111 bool operator==(const iterator_self_type aOther) { 1112 MOZ_ASSERT(mListLink); 1113 NS_ASSERTION(mListLink == aOther.mListLink, 1114 "comparing iterators over different lists"); 1115 return mCurrent == aOther.mCurrent; 1116 } 1117 bool operator!=(const iterator_self_type aOther) { 1118 MOZ_ASSERT(mListLink); 1119 NS_ASSERTION(mListLink == aOther.mListLink, 1120 "comparing iterators over different lists"); 1121 return mCurrent != aOther.mCurrent; 1122 } 1123 1124 #ifdef DEBUG IsInSameList(const iterator_self_type aOther)1125 bool IsInSameList(const iterator_self_type aOther) const { 1126 return mListLink == aOther.mListLink; 1127 } 1128 #endif 1129 1130 private: 1131 const link_type* mCurrent; 1132 #ifdef DEBUG 1133 const link_type* mListLink; // the list's link, i.e., the end 1134 #endif 1135 }; 1136 1137 class nsLineList_const_reverse_iterator { 1138 public: 1139 friend class nsLineList; 1140 friend class nsLineList_iterator; 1141 friend class nsLineList_reverse_iterator; 1142 friend class nsLineList_const_iterator; 1143 1144 typedef nsLineList_const_reverse_iterator iterator_self_type; 1145 typedef nsLineList_const_iterator iterator_reverse_type; 1146 typedef nsLineList_iterator iterator_nonconst_reverse_type; 1147 typedef nsLineList_reverse_iterator iterator_nonconst_type; 1148 1149 typedef nsLineBox& reference; 1150 typedef const nsLineBox& const_reference; 1151 1152 typedef nsLineBox* pointer; 1153 typedef const nsLineBox* const_pointer; 1154 1155 typedef uint32_t size_type; 1156 typedef int32_t difference_type; 1157 1158 typedef nsLineLink link_type; 1159 1160 #ifdef DEBUG nsLineList_const_reverse_iterator()1161 nsLineList_const_reverse_iterator() : mListLink(nullptr) { 1162 memset(&mCurrent, 0xcd, sizeof(mCurrent)); 1163 } 1164 #else 1165 // Auto generated default constructor OK. 1166 #endif 1167 // Auto generated copy-constructor OK. 1168 1169 inline iterator_self_type& operator=(const iterator_nonconst_type& aOther); 1170 inline iterator_self_type& operator=( 1171 const iterator_nonconst_reverse_type& aOther); 1172 inline iterator_self_type& operator=(const iterator_self_type& aOther); 1173 inline iterator_self_type& operator=(const iterator_reverse_type& aOther); 1174 1175 iterator_self_type& operator++() { 1176 mCurrent = mCurrent->_mPrev; 1177 return *this; 1178 } 1179 1180 iterator_self_type operator++(int) { 1181 iterator_self_type rv(*this); 1182 mCurrent = mCurrent->_mPrev; 1183 return rv; 1184 } 1185 1186 iterator_self_type& operator--() { 1187 mCurrent = mCurrent->_mNext; 1188 return *this; 1189 } 1190 1191 iterator_self_type operator--(int) { 1192 iterator_self_type rv(*this); 1193 mCurrent = mCurrent->_mNext; 1194 return rv; 1195 } 1196 1197 const_reference operator*() const { 1198 MOZ_ASSERT(mListLink); 1199 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1200 return *static_cast<const_pointer>(mCurrent); 1201 } 1202 1203 const_pointer operator->() const { 1204 MOZ_ASSERT(mListLink); 1205 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1206 return static_cast<const_pointer>(mCurrent); 1207 } 1208 get()1209 const_pointer get() const { 1210 MOZ_ASSERT(mListLink); 1211 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1212 return static_cast<const_pointer>(mCurrent); 1213 } 1214 1215 #ifndef __MWERKS__ const_pointer()1216 operator const_pointer() const { 1217 MOZ_ASSERT(mListLink); 1218 MOZ_ASSERT(mCurrent != mListLink, "running past end"); 1219 return static_cast<const_pointer>(mCurrent); 1220 } 1221 #endif /* !__MWERKS__ */ 1222 1223 // Passing by value rather than by reference and reference to const 1224 // to keep AIX happy. 1225 bool operator==(const iterator_self_type aOther) const { 1226 MOZ_ASSERT(mListLink); 1227 NS_ASSERTION(mListLink == aOther.mListLink, 1228 "comparing iterators over different lists"); 1229 return mCurrent == aOther.mCurrent; 1230 } 1231 bool operator!=(const iterator_self_type aOther) const { 1232 MOZ_ASSERT(mListLink); 1233 NS_ASSERTION(mListLink == aOther.mListLink, 1234 "comparing iterators over different lists"); 1235 return mCurrent != aOther.mCurrent; 1236 } 1237 bool operator==(const iterator_self_type aOther) { 1238 MOZ_ASSERT(mListLink); 1239 NS_ASSERTION(mListLink == aOther.mListLink, 1240 "comparing iterators over different lists"); 1241 return mCurrent == aOther.mCurrent; 1242 } 1243 bool operator!=(const iterator_self_type aOther) { 1244 MOZ_ASSERT(mListLink); 1245 NS_ASSERTION(mListLink == aOther.mListLink, 1246 "comparing iterators over different lists"); 1247 return mCurrent != aOther.mCurrent; 1248 } 1249 1250 #ifdef DEBUG IsInSameList(const iterator_self_type aOther)1251 bool IsInSameList(const iterator_self_type aOther) const { 1252 return mListLink == aOther.mListLink; 1253 } 1254 #endif 1255 1256 // private: 1257 const link_type* mCurrent; 1258 #ifdef DEBUG 1259 const link_type* mListLink; // the list's link, i.e., the end 1260 #endif 1261 }; 1262 1263 class nsLineList { 1264 public: 1265 friend class nsLineList_iterator; 1266 friend class nsLineList_reverse_iterator; 1267 friend class nsLineList_const_iterator; 1268 friend class nsLineList_const_reverse_iterator; 1269 1270 typedef uint32_t size_type; 1271 typedef int32_t difference_type; 1272 1273 typedef nsLineLink link_type; 1274 1275 private: 1276 link_type mLink; 1277 1278 public: 1279 typedef nsLineList self_type; 1280 1281 typedef nsLineBox& reference; 1282 typedef const nsLineBox& const_reference; 1283 1284 typedef nsLineBox* pointer; 1285 typedef const nsLineBox* const_pointer; 1286 1287 typedef nsLineList_iterator iterator; 1288 typedef nsLineList_reverse_iterator reverse_iterator; 1289 typedef nsLineList_const_iterator const_iterator; 1290 typedef nsLineList_const_reverse_iterator const_reverse_iterator; 1291 nsLineList()1292 nsLineList() { 1293 MOZ_COUNT_CTOR(nsLineList); 1294 clear(); 1295 } 1296 MOZ_COUNTED_DTOR(nsLineList)1297 MOZ_COUNTED_DTOR(nsLineList) 1298 1299 const_iterator begin() const { 1300 const_iterator rv; 1301 rv.mCurrent = mLink._mNext; 1302 #ifdef DEBUG 1303 rv.mListLink = &mLink; 1304 #endif 1305 return rv; 1306 } 1307 begin()1308 iterator begin() { 1309 iterator rv; 1310 rv.mCurrent = mLink._mNext; 1311 #ifdef DEBUG 1312 rv.mListLink = &mLink; 1313 #endif 1314 return rv; 1315 } 1316 begin(nsLineBox * aLine)1317 iterator begin(nsLineBox* aLine) { 1318 iterator rv; 1319 rv.mCurrent = aLine; 1320 #ifdef DEBUG 1321 rv.mListLink = &mLink; 1322 #endif 1323 return rv; 1324 } 1325 end()1326 const_iterator end() const { 1327 const_iterator rv; 1328 rv.mCurrent = &mLink; 1329 #ifdef DEBUG 1330 rv.mListLink = &mLink; 1331 #endif 1332 return rv; 1333 } 1334 end()1335 iterator end() { 1336 iterator rv; 1337 rv.mCurrent = &mLink; 1338 #ifdef DEBUG 1339 rv.mListLink = &mLink; 1340 #endif 1341 return rv; 1342 } 1343 rbegin()1344 const_reverse_iterator rbegin() const { 1345 const_reverse_iterator rv; 1346 rv.mCurrent = mLink._mPrev; 1347 #ifdef DEBUG 1348 rv.mListLink = &mLink; 1349 #endif 1350 return rv; 1351 } 1352 rbegin()1353 reverse_iterator rbegin() { 1354 reverse_iterator rv; 1355 rv.mCurrent = mLink._mPrev; 1356 #ifdef DEBUG 1357 rv.mListLink = &mLink; 1358 #endif 1359 return rv; 1360 } 1361 rbegin(nsLineBox * aLine)1362 reverse_iterator rbegin(nsLineBox* aLine) { 1363 reverse_iterator rv; 1364 rv.mCurrent = aLine; 1365 #ifdef DEBUG 1366 rv.mListLink = &mLink; 1367 #endif 1368 return rv; 1369 } 1370 rend()1371 const_reverse_iterator rend() const { 1372 const_reverse_iterator rv; 1373 rv.mCurrent = &mLink; 1374 #ifdef DEBUG 1375 rv.mListLink = &mLink; 1376 #endif 1377 return rv; 1378 } 1379 rend()1380 reverse_iterator rend() { 1381 reverse_iterator rv; 1382 rv.mCurrent = &mLink; 1383 #ifdef DEBUG 1384 rv.mListLink = &mLink; 1385 #endif 1386 return rv; 1387 } 1388 empty()1389 bool empty() const { return mLink._mNext == &mLink; } 1390 1391 // NOTE: O(N). size()1392 size_type size() const { 1393 size_type count = 0; 1394 for (const link_type* cur = mLink._mNext; cur != &mLink; 1395 cur = cur->_mNext) { 1396 ++count; 1397 } 1398 return count; 1399 } 1400 front()1401 pointer front() { 1402 NS_ASSERTION(!empty(), "no element to return"); 1403 return static_cast<pointer>(mLink._mNext); 1404 } 1405 front()1406 const_pointer front() const { 1407 NS_ASSERTION(!empty(), "no element to return"); 1408 return static_cast<const_pointer>(mLink._mNext); 1409 } 1410 back()1411 pointer back() { 1412 NS_ASSERTION(!empty(), "no element to return"); 1413 return static_cast<pointer>(mLink._mPrev); 1414 } 1415 back()1416 const_pointer back() const { 1417 NS_ASSERTION(!empty(), "no element to return"); 1418 return static_cast<const_pointer>(mLink._mPrev); 1419 } 1420 push_front(pointer aNew)1421 void push_front(pointer aNew) { 1422 aNew->_mNext = mLink._mNext; 1423 mLink._mNext->_mPrev = aNew; 1424 aNew->_mPrev = &mLink; 1425 mLink._mNext = aNew; 1426 } 1427 pop_front()1428 void pop_front() 1429 // NOTE: leaves dangling next/prev pointers 1430 { 1431 NS_ASSERTION(!empty(), "no element to pop"); 1432 link_type* newFirst = mLink._mNext->_mNext; 1433 newFirst->_mPrev = &mLink; 1434 // mLink._mNext->_mNext = nullptr; 1435 // mLink._mNext->_mPrev = nullptr; 1436 mLink._mNext = newFirst; 1437 } 1438 push_back(pointer aNew)1439 void push_back(pointer aNew) { 1440 aNew->_mPrev = mLink._mPrev; 1441 mLink._mPrev->_mNext = aNew; 1442 aNew->_mNext = &mLink; 1443 mLink._mPrev = aNew; 1444 } 1445 pop_back()1446 void pop_back() 1447 // NOTE: leaves dangling next/prev pointers 1448 { 1449 NS_ASSERTION(!empty(), "no element to pop"); 1450 link_type* newLast = mLink._mPrev->_mPrev; 1451 newLast->_mNext = &mLink; 1452 // mLink._mPrev->_mPrev = nullptr; 1453 // mLink._mPrev->_mNext = nullptr; 1454 mLink._mPrev = newLast; 1455 } 1456 1457 // inserts x before position before_insert(iterator position,pointer x)1458 iterator before_insert(iterator position, pointer x) { 1459 // use |mCurrent| to prevent DEBUG_PASS_END assertions 1460 x->_mPrev = position.mCurrent->_mPrev; 1461 x->_mNext = position.mCurrent; 1462 position.mCurrent->_mPrev->_mNext = x; 1463 position.mCurrent->_mPrev = x; 1464 return --position; 1465 } 1466 1467 // inserts x after position after_insert(iterator position,pointer x)1468 iterator after_insert(iterator position, pointer x) { 1469 // use |mCurrent| to prevent DEBUG_PASS_END assertions 1470 x->_mNext = position.mCurrent->_mNext; 1471 x->_mPrev = position.mCurrent; 1472 position.mCurrent->_mNext->_mPrev = x; 1473 position.mCurrent->_mNext = x; 1474 return ++position; 1475 } 1476 1477 // returns iterator pointing to after the element erase(iterator position)1478 iterator erase(iterator position) 1479 // NOTE: leaves dangling next/prev pointers 1480 { 1481 position->_mPrev->_mNext = position->_mNext; 1482 position->_mNext->_mPrev = position->_mPrev; 1483 return ++position; 1484 } 1485 swap(self_type & y)1486 void swap(self_type& y) { 1487 link_type tmp(y.mLink); 1488 y.mLink = mLink; 1489 mLink = tmp; 1490 1491 if (!empty()) { 1492 mLink._mNext->_mPrev = &mLink; 1493 mLink._mPrev->_mNext = &mLink; 1494 } 1495 1496 if (!y.empty()) { 1497 y.mLink._mNext->_mPrev = &y.mLink; 1498 y.mLink._mPrev->_mNext = &y.mLink; 1499 } 1500 } 1501 clear()1502 void clear() 1503 // NOTE: leaves dangling next/prev pointers 1504 { 1505 mLink._mNext = &mLink; 1506 mLink._mPrev = &mLink; 1507 } 1508 1509 // inserts the conts of x before position and makes x empty splice(iterator position,self_type & x)1510 void splice(iterator position, self_type& x) { 1511 // use |mCurrent| to prevent DEBUG_PASS_END assertions 1512 position.mCurrent->_mPrev->_mNext = x.mLink._mNext; 1513 x.mLink._mNext->_mPrev = position.mCurrent->_mPrev; 1514 x.mLink._mPrev->_mNext = position.mCurrent; 1515 position.mCurrent->_mPrev = x.mLink._mPrev; 1516 x.clear(); 1517 } 1518 1519 // Inserts element *i from list x before position and removes 1520 // it from x. splice(iterator position,self_type & x,iterator i)1521 void splice(iterator position, self_type& x, iterator i) { 1522 NS_ASSERTION(!x.empty(), "Can't insert from empty list."); 1523 NS_ASSERTION(position != i && position.mCurrent != i->_mNext, 1524 "We don't check for this case."); 1525 1526 // remove from |x| 1527 i->_mPrev->_mNext = i->_mNext; 1528 i->_mNext->_mPrev = i->_mPrev; 1529 1530 // use |mCurrent| to prevent DEBUG_PASS_END assertions 1531 // link into |this|, before-side 1532 i->_mPrev = position.mCurrent->_mPrev; 1533 position.mCurrent->_mPrev->_mNext = i.get(); 1534 1535 // link into |this|, after-side 1536 i->_mNext = position.mCurrent; 1537 position.mCurrent->_mPrev = i.get(); 1538 } 1539 1540 // Inserts elements in [|first|, |last|), which are in |x|, 1541 // into |this| before |position| and removes them from |x|. splice(iterator position,self_type & x,iterator first,iterator last)1542 void splice(iterator position, self_type& x, iterator first, iterator last) { 1543 NS_ASSERTION(!x.empty(), "Can't insert from empty list."); 1544 1545 if (first == last) return; 1546 1547 --last; // so we now want to move [first, last] 1548 // remove from |x| 1549 first->_mPrev->_mNext = last->_mNext; 1550 last->_mNext->_mPrev = first->_mPrev; 1551 1552 // use |mCurrent| to prevent DEBUG_PASS_END assertions 1553 // link into |this|, before-side 1554 first->_mPrev = position.mCurrent->_mPrev; 1555 position.mCurrent->_mPrev->_mNext = first.get(); 1556 1557 // link into |this|, after-side 1558 last->_mNext = position.mCurrent; 1559 position.mCurrent->_mPrev = last.get(); 1560 } 1561 }; 1562 1563 // Many of these implementations of operator= don't work yet. I don't 1564 // know why. 1565 1566 #ifdef DEBUG 1567 1568 // NOTE: ASSIGN_FROM is meant to be used *only* as the entire body 1569 // of a function and therefore lacks PR_{BEGIN,END}_MACRO 1570 # define ASSIGN_FROM(other_) \ 1571 mCurrent = other_.mCurrent; \ 1572 mListLink = other_.mListLink; \ 1573 return *this; 1574 1575 #else /* !NS_LINELIST_DEBUG_PASS_END */ 1576 1577 # define ASSIGN_FROM(other_) \ 1578 mCurrent = other_.mCurrent; \ 1579 return *this; 1580 1581 #endif /* !NS_LINELIST_DEBUG_PASS_END */ 1582 1583 inline nsLineList_iterator& nsLineList_iterator::operator=( 1584 const nsLineList_iterator& aOther) = default; 1585 1586 inline nsLineList_iterator& nsLineList_iterator::operator=( 1587 const nsLineList_reverse_iterator& aOther) { 1588 ASSIGN_FROM(aOther) 1589 } 1590 1591 inline nsLineList_reverse_iterator& nsLineList_reverse_iterator::operator=( 1592 const nsLineList_iterator& aOther) { 1593 ASSIGN_FROM(aOther) 1594 } 1595 1596 inline nsLineList_reverse_iterator& nsLineList_reverse_iterator::operator=( 1597 const nsLineList_reverse_iterator& aOther) = default; 1598 1599 inline nsLineList_const_iterator& nsLineList_const_iterator::operator=( 1600 const nsLineList_iterator& aOther) { 1601 ASSIGN_FROM(aOther) 1602 } 1603 1604 inline nsLineList_const_iterator& nsLineList_const_iterator::operator=( 1605 const nsLineList_reverse_iterator& aOther) { 1606 ASSIGN_FROM(aOther) 1607 } 1608 1609 inline nsLineList_const_iterator& nsLineList_const_iterator::operator=( 1610 const nsLineList_const_iterator& aOther) = default; 1611 1612 inline nsLineList_const_iterator& nsLineList_const_iterator::operator=( 1613 const nsLineList_const_reverse_iterator& aOther) { 1614 ASSIGN_FROM(aOther) 1615 } 1616 1617 inline nsLineList_const_reverse_iterator& 1618 nsLineList_const_reverse_iterator::operator=( 1619 const nsLineList_iterator& aOther) { 1620 ASSIGN_FROM(aOther) 1621 } 1622 1623 inline nsLineList_const_reverse_iterator& 1624 nsLineList_const_reverse_iterator::operator=( 1625 const nsLineList_reverse_iterator& aOther) { 1626 ASSIGN_FROM(aOther) 1627 } 1628 1629 inline nsLineList_const_reverse_iterator& 1630 nsLineList_const_reverse_iterator::operator=( 1631 const nsLineList_const_iterator& aOther) { 1632 ASSIGN_FROM(aOther) 1633 } 1634 1635 inline nsLineList_const_reverse_iterator& 1636 nsLineList_const_reverse_iterator::operator=( 1637 const nsLineList_const_reverse_iterator& aOther) = default; 1638 1639 //---------------------------------------------------------------------- 1640 1641 class nsLineIterator final : public nsILineIterator { 1642 public: 1643 nsLineIterator(); 1644 ~nsLineIterator(); 1645 1646 virtual void DisposeLineIterator() override; 1647 1648 virtual int32_t GetNumLines() const override; 1649 virtual bool GetDirection() override; 1650 NS_IMETHOD GetLine(int32_t aLineNumber, nsIFrame** aFirstFrameOnLine, 1651 int32_t* aNumFramesOnLine, 1652 nsRect& aLineBounds) const override; 1653 virtual int32_t FindLineContaining(nsIFrame* aFrame, 1654 int32_t aStartLine = 0) override; 1655 NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos, 1656 nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame, 1657 bool* aPosIsAfterLastFrame) const override; 1658 1659 NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, 1660 int32_t aLineNumber) const override; 1661 NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered, 1662 nsIFrame** aFirstVisual, 1663 nsIFrame** aLastVisual) override; 1664 nsresult Init(nsLineList& aLines, bool aRightToLeft); 1665 1666 private: PrevLine()1667 nsLineBox* PrevLine() { 1668 if (0 == mIndex) { 1669 return nullptr; 1670 } 1671 return mLines[--mIndex]; 1672 } 1673 NextLine()1674 nsLineBox* NextLine() { 1675 if (mIndex >= mNumLines - 1) { 1676 return nullptr; 1677 } 1678 return mLines[++mIndex]; 1679 } 1680 LineAt(int32_t aIndex)1681 nsLineBox* LineAt(int32_t aIndex) { 1682 if ((aIndex < 0) || (aIndex >= mNumLines)) { 1683 return nullptr; 1684 } 1685 return mLines[aIndex]; 1686 } 1687 1688 nsLineBox** mLines; 1689 int32_t mIndex; 1690 int32_t mNumLines; 1691 bool mRightToLeft; 1692 }; 1693 1694 #endif /* nsLineBox_h___ */ 1695