Coverage Report

Created: 2018-09-25 14:53

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