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