Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:ts=2:et:sw=2:
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/. */
7 /* representation of one line within a block frame, a CSS line box */
9 #ifndef nsLineBox_h___
10 #define nsLineBox_h___
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Likely.h"
15 #include "nsILineIterator.h"
16 #include "nsIFrame.h"
17 #include <algorithm>
19 class nsLineBox;
20 class nsFloatCache;
21 class nsFloatCacheList;
22 class nsFloatCacheFreeList;
24 // State cached after reflowing a float. This state is used during
25 // incremental reflow when we avoid reflowing a float.
26 class nsFloatCache {
27 public:
28 nsFloatCache();
29 #ifdef NS_BUILD_REFCNT_LOGGING
30 ~nsFloatCache();
31 #else
32 ~nsFloatCache() { }
33 #endif
35 nsFloatCache* Next() const { return mNext; }
37 nsIFrame* mFloat; // floating frame
39 protected:
40 nsFloatCache* mNext;
42 friend class nsFloatCacheList;
43 friend class nsFloatCacheFreeList;
44 };
46 //----------------------------------------
48 class nsFloatCacheList {
49 public:
50 #ifdef NS_BUILD_REFCNT_LOGGING
51 nsFloatCacheList();
52 #else
53 nsFloatCacheList() : mHead(nullptr) { }
54 #endif
55 ~nsFloatCacheList();
57 bool IsEmpty() const {
58 return nullptr == mHead;
59 }
61 bool NotEmpty() const {
62 return nullptr != mHead;
63 }
65 nsFloatCache* Head() const {
66 return mHead;
67 }
69 nsFloatCache* Tail() const;
71 void DeleteAll();
73 nsFloatCache* Find(nsIFrame* aOutOfFlowFrame);
75 // Remove a nsFloatCache from this list. Deleting this nsFloatCache
76 // becomes the caller's responsibility.
77 void Remove(nsFloatCache* aElement) { RemoveAndReturnPrev(aElement); }
79 // Steal away aList's nsFloatCache objects and put them in this
80 // list. aList must not be empty.
81 void Append(nsFloatCacheFreeList& aList);
83 protected:
84 nsFloatCache* mHead;
86 // Remove a nsFloatCache from this list. Deleting this nsFloatCache
87 // becomes the caller's responsibility. Returns the nsFloatCache that was
88 // before aElement, or nullptr if aElement was the first.
89 nsFloatCache* RemoveAndReturnPrev(nsFloatCache* aElement);
91 friend class nsFloatCacheFreeList;
92 };
94 //---------------------------------------
95 // Like nsFloatCacheList, but with fast access to the tail
97 class nsFloatCacheFreeList : private nsFloatCacheList {
98 public:
99 #ifdef NS_BUILD_REFCNT_LOGGING
100 nsFloatCacheFreeList();
101 ~nsFloatCacheFreeList();
102 #else
103 nsFloatCacheFreeList() : mTail(nullptr) { }
104 ~nsFloatCacheFreeList() { }
105 #endif
107 // Reimplement trivial functions
108 bool IsEmpty() const {
109 return nullptr == mHead;
110 }
112 nsFloatCache* Head() const {
113 return mHead;
114 }
116 nsFloatCache* Tail() const {
117 return mTail;
118 }
120 bool NotEmpty() const {
121 return nullptr != mHead;
122 }
124 void DeleteAll();
126 // Steal away aList's nsFloatCache objects and put them on this
127 // free-list. aList must not be empty.
128 void Append(nsFloatCacheList& aList);
130 void Append(nsFloatCache* aFloatCache);
132 void Remove(nsFloatCache* aElement);
134 // Remove an nsFloatCache object from this list and return it, or create
135 // a new one if this one is empty; Set its mFloat to aFloat.
136 nsFloatCache* Alloc(nsIFrame* aFloat);
138 protected:
139 nsFloatCache* mTail;
141 friend class nsFloatCacheList;
142 };
144 //----------------------------------------------------------------------
146 #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1)
147 #define LINE_MAX_CHILD_COUNT INT32_MAX
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);
166 class nsLineList;
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;
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 */
183 class nsLineLink {
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;
192 private:
193 nsLineLink *_mNext; // or head
194 nsLineLink *_mPrev; // or tail
196 };
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 MOZ_FINAL : public nsLineLink {
205 private:
206 nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock);
207 ~nsLineBox();
209 // Overloaded new operator. Uses an arena (which comes from the presShell)
210 // to perform the allocation.
211 void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
212 void operator delete(void* aPtr, size_t sz) MOZ_DELETE;
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);
222 // mBlock bit
223 bool IsBlock() const {
224 return mFlags.mBlock;
225 }
226 bool IsInline() const {
227 return 0 == mFlags.mBlock;
228 }
230 // mDirty bit
231 void MarkDirty() {
232 mFlags.mDirty = 1;
233 }
234 void ClearDirty() {
235 mFlags.mDirty = 0;
236 }
237 bool IsDirty() const {
238 return mFlags.mDirty;
239 }
241 // mPreviousMarginDirty bit
242 void MarkPreviousMarginDirty() {
243 mFlags.mPreviousMarginDirty = 1;
244 }
245 void ClearPreviousMarginDirty() {
246 mFlags.mPreviousMarginDirty = 0;
247 }
248 bool IsPreviousMarginDirty() const {
249 return mFlags.mPreviousMarginDirty;
250 }
252 // mHasClearance bit
253 void SetHasClearance() {
254 mFlags.mHasClearance = 1;
255 }
256 void ClearHasClearance() {
257 mFlags.mHasClearance = 0;
258 }
259 bool HasClearance() const {
260 return mFlags.mHasClearance;
261 }
263 // mImpactedByFloat bit
264 void SetLineIsImpactedByFloat(bool aValue) {
265 mFlags.mImpactedByFloat = aValue;
266 }
267 bool IsImpactedByFloat() const {
268 return mFlags.mImpactedByFloat;
269 }
271 // mLineWrapped bit
272 void SetLineWrapped(bool aOn) {
273 mFlags.mLineWrapped = aOn;
274 }
275 bool IsLineWrapped() const {
276 return mFlags.mLineWrapped;
277 }
279 // mInvalidateTextRuns bit
280 void SetInvalidateTextRuns(bool aOn) {
281 mFlags.mInvalidateTextRuns = aOn;
282 }
283 bool GetInvalidateTextRuns() const {
284 return mFlags.mInvalidateTextRuns;
285 }
287 // mResizeReflowOptimizationDisabled bit
288 void DisableResizeReflowOptimization() {
289 mFlags.mResizeReflowOptimizationDisabled = true;
290 }
291 void EnableResizeReflowOptimization() {
292 mFlags.mResizeReflowOptimizationDisabled = false;
293 }
294 bool ResizeReflowOptimizationDisabled() const {
295 return mFlags.mResizeReflowOptimizationDisabled;
296 }
298 // mHasBullet bit
299 void SetHasBullet() {
300 mFlags.mHasBullet = true;
301 InvalidateCachedIsEmpty();
302 }
303 void ClearHasBullet() {
304 mFlags.mHasBullet = false;
305 InvalidateCachedIsEmpty();
306 }
307 bool HasBullet() const {
308 return mFlags.mHasBullet;
309 }
311 // mHadFloatPushed bit
312 void SetHadFloatPushed() {
313 mFlags.mHadFloatPushed = true;
314 }
315 void ClearHadFloatPushed() {
316 mFlags.mHadFloatPushed = false;
317 }
318 bool HadFloatPushed() const {
319 return mFlags.mHadFloatPushed;
320 }
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;
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);
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);
340 void SwitchToHashtable()
341 {
342 MOZ_ASSERT(!mFlags.mHasHashedFrames);
343 uint32_t count = GetChildCount();
344 mFlags.mHasHashedFrames = 1;
345 uint32_t minSize =
346 std::max(kMinChildCountForHashtable, uint32_t(PL_DHASH_MIN_SIZE));
347 mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >(std::max(count, minSize));
348 for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
349 mFrames->PutEntry(f);
350 }
351 }
352 void SwitchToCounter() {
353 MOZ_ASSERT(mFlags.mHasHashedFrames);
354 uint32_t count = GetChildCount();
355 delete mFrames;
356 mFlags.mHasHashedFrames = 0;
357 mChildCount = count;
358 }
360 public:
361 int32_t GetChildCount() const {
362 return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() : mChildCount;
363 }
365 /**
366 * Register that aFrame is now on this line.
367 */
368 void NoteFrameAdded(nsIFrame* aFrame) {
369 if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) {
370 mFrames->PutEntry(aFrame);
371 } else {
372 if (++mChildCount >= kMinChildCountForHashtable) {
373 SwitchToHashtable();
374 }
375 }
376 }
378 /**
379 * Register that aFrame is not on this line anymore.
380 */
381 void NoteFrameRemoved(nsIFrame* aFrame) {
382 MOZ_ASSERT(GetChildCount() > 0);
383 if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) {
384 mFrames->RemoveEntry(aFrame);
385 if (mFrames->Count() < kMinChildCountForHashtable) {
386 SwitchToCounter();
387 }
388 } else {
389 --mChildCount;
390 }
391 }
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 bool HasBreakBefore() const {
398 return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
399 }
400 void SetBreakTypeBefore(uint8_t aBreakType) {
401 NS_ASSERTION(IsBlock(), "Only blocks have break-before");
402 NS_ASSERTION(aBreakType == NS_STYLE_CLEAR_NONE ||
403 aBreakType == NS_STYLE_CLEAR_LEFT ||
404 aBreakType == NS_STYLE_CLEAR_RIGHT ||
405 aBreakType == NS_STYLE_CLEAR_BOTH,
406 "Only float break types are allowed before a line");
407 mFlags.mBreakType = aBreakType;
408 }
409 uint8_t GetBreakTypeBefore() const {
410 return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
411 }
413 bool HasBreakAfter() const {
414 return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
415 }
416 void SetBreakTypeAfter(uint8_t aBreakType) {
417 NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
418 NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
419 mFlags.mBreakType = aBreakType;
420 }
421 bool HasFloatBreakAfter() const {
422 return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
423 NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
424 NS_STYLE_CLEAR_BOTH == mFlags.mBreakType);
425 }
426 uint8_t GetBreakTypeAfter() const {
427 return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
428 }
430 // mCarriedOutBottomMargin value
431 nsCollapsingMargin GetCarriedOutBottomMargin() const;
432 // Returns true if the margin changed
433 bool SetCarriedOutBottomMargin(nsCollapsingMargin aValue);
435 // mFloats
436 bool HasFloats() const {
437 return (IsInline() && mInlineData) && mInlineData->mFloats.NotEmpty();
438 }
439 nsFloatCache* GetFirstFloat();
440 void FreeFloats(nsFloatCacheFreeList& aFreeList);
441 void AppendFloats(nsFloatCacheFreeList& aFreeList);
442 bool RemoveFloat(nsIFrame* aFrame);
444 // Combined area is the area of the line that should influence the
445 // overflow area of its parent block. The combined area should be
446 // used for painting-related things, but should never be used for
447 // layout (except for handling of 'overflow').
448 void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
449 nsRect GetOverflowArea(nsOverflowType aType) {
450 return mData ? mData->mOverflowAreas.Overflow(aType) : GetPhysicalBounds();
451 }
452 nsOverflowAreas GetOverflowAreas() {
453 if (mData) {
454 return mData->mOverflowAreas;
455 }
456 nsRect bounds = GetPhysicalBounds();
457 return nsOverflowAreas(bounds, bounds);
458 }
459 nsRect GetVisualOverflowArea()
460 { return GetOverflowArea(eVisualOverflow); }
461 nsRect GetScrollableOverflowArea()
462 { return GetOverflowArea(eScrollableOverflow); }
464 void SlideBy(nscoord aDBCoord, nscoord aContainerWidth) {
465 NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1,
466 "container width doesn't match");
467 mContainerWidth = aContainerWidth;
468 mBounds.BStart(mWritingMode) += aDBCoord;
469 if (mData) {
470 NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
471 mData->mOverflowAreas.Overflow(otype).y += aDBCoord;
472 }
473 }
474 }
476 void IndentBy(nscoord aDICoord, nscoord aContainerWidth) {
477 NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1,
478 "container width doesn't match");
479 mContainerWidth = aContainerWidth;
480 mBounds.IStart(mWritingMode) += aDICoord;
481 }
483 void ExpandBy(nscoord aDISize, nscoord aContainerWidth) {
484 NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1,
485 "container width doesn't match");
486 mContainerWidth = aContainerWidth;
487 mBounds.ISize(mWritingMode) += aDISize;
488 }
490 /**
491 * The ascent (distance from top to baseline) of the linebox is the
492 * ascent of the anonymous inline box (for which we don't actually
493 * create a frame) that wraps all the consecutive inline children of a
494 * block.
495 *
496 * This is currently unused for block lines.
497 */
498 nscoord GetAscent() const { return mAscent; }
499 void SetAscent(nscoord aAscent) { mAscent = aAscent; }
501 nscoord BStart() const {
502 return mBounds.BStart(mWritingMode);
503 }
504 nscoord BSize() const {
505 return mBounds.BSize(mWritingMode);
506 }
507 nscoord BEnd() const {
508 return mBounds.BEnd(mWritingMode);
509 }
510 nscoord IStart() const {
511 return mBounds.IStart(mWritingMode);
512 }
513 nscoord ISize() const {
514 return mBounds.ISize(mWritingMode);
515 }
516 nscoord IEnd() const {
517 return mBounds.IEnd(mWritingMode);
518 }
519 void SetBoundsEmpty() {
520 mBounds.IStart(mWritingMode) = 0;
521 mBounds.ISize(mWritingMode) = 0;
522 mBounds.BStart(mWritingMode) = 0;
523 mBounds.BSize(mWritingMode) = 0;
524 }
526 static void DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
527 nsIFrame* aDestructRoot, nsFrameList* aFrames);
529 // search from end to beginning of [aBegin, aEnd)
530 // Returns true if it found the line and false if not.
531 // Moves aEnd as it searches so that aEnd points to the resulting line.
532 // aLastFrameBeforeEnd is the last frame before aEnd (so if aEnd is
533 // the end of the line list, it's just the last frame in the frame
534 // list).
535 static bool RFindLineContaining(nsIFrame* aFrame,
536 const nsLineList_iterator& aBegin,
537 nsLineList_iterator& aEnd,
538 nsIFrame* aLastFrameBeforeEnd,
539 int32_t* aFrameIndexInLine);
541 #ifdef DEBUG_FRAME_DUMP
542 char* StateToString(char* aBuf, int32_t aBufSize) const;
544 void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
545 void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
546 nsIFrame* LastChild() const;
547 #endif
549 private:
550 int32_t IndexOf(nsIFrame* aFrame) const;
551 public:
553 bool Contains(nsIFrame* aFrame) const {
554 return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame)
555 : IndexOf(aFrame) >= 0;
556 }
558 // whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
559 bool IsEmpty() const;
561 // Call this only while in Reflow() for the block the line belongs
562 // to, only between reflowing the line (or sliding it, if we skip
563 // reflowing it) and the end of reflowing the block.
564 bool CachedIsEmpty();
566 void InvalidateCachedIsEmpty() {
567 mFlags.mEmptyCacheValid = false;
568 }
570 // For debugging purposes
571 bool IsValidCachedIsEmpty() {
572 return mFlags.mEmptyCacheValid;
573 }
575 #ifdef DEBUG
576 static int32_t GetCtorCount();
577 #endif
579 nsIFrame* mFirstChild;
581 mozilla::WritingMode mWritingMode;
582 nscoord mContainerWidth;
583 private:
584 mozilla::LogicalRect mBounds;
585 public:
586 const mozilla::LogicalRect& GetBounds() { return mBounds; }
587 nsRect GetPhysicalBounds() const
588 {
589 if (mBounds.IsEmpty()) {
590 return nsRect(0, 0, 0, 0);
591 }
593 NS_ASSERTION(mContainerWidth != -1, "mContainerWidth not initialized");
594 return mBounds.GetPhysicalRect(mWritingMode, mContainerWidth);
595 }
596 void SetBounds(mozilla::WritingMode aWritingMode,
597 nscoord aIStart, nscoord aBStart,
598 nscoord aISize, nscoord aBSize,
599 nscoord aContainerWidth)
600 {
601 mWritingMode = aWritingMode;
602 mContainerWidth = aContainerWidth;
603 mBounds = mozilla::LogicalRect(aWritingMode, aIStart, aBStart,
604 aISize, aBSize);
605 }
606 void SetBounds(mozilla::WritingMode aWritingMode,
607 nsRect aRect, nscoord aContainerWidth)
608 {
609 mWritingMode = aWritingMode;
610 mContainerWidth = aContainerWidth;
611 mBounds = mozilla::LogicalRect(aWritingMode, aRect, aContainerWidth);
612 }
614 // mFlags.mHasHashedFrames says which one to use
615 union {
616 nsTHashtable< nsPtrHashKey<nsIFrame> >* mFrames;
617 uint32_t mChildCount;
618 };
620 struct FlagBits {
621 uint32_t mDirty : 1;
622 uint32_t mPreviousMarginDirty : 1;
623 uint32_t mHasClearance : 1;
624 uint32_t mBlock : 1;
625 uint32_t mImpactedByFloat : 1;
626 uint32_t mLineWrapped: 1;
627 uint32_t mInvalidateTextRuns : 1;
628 uint32_t mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow
629 uint32_t mEmptyCacheValid: 1;
630 uint32_t mEmptyCacheState: 1;
631 // mHasBullet indicates that this is an inline line whose block's
632 // bullet is adjacent to this line and non-empty.
633 uint32_t mHasBullet : 1;
634 // Indicates that this line *may* have a placeholder for a float
635 // that was pushed to a later column or page.
636 uint32_t mHadFloatPushed : 1;
637 uint32_t mHasHashedFrames: 1;
638 uint32_t mBreakType : 4;
639 };
641 struct ExtraData {
642 ExtraData(const nsRect& aBounds) : mOverflowAreas(aBounds, aBounds) {
643 }
644 nsOverflowAreas mOverflowAreas;
645 };
647 struct ExtraBlockData : public ExtraData {
648 ExtraBlockData(const nsRect& aBounds)
649 : ExtraData(aBounds),
650 mCarriedOutBottomMargin()
651 {
652 }
653 nsCollapsingMargin mCarriedOutBottomMargin;
654 };
656 struct ExtraInlineData : public ExtraData {
657 ExtraInlineData(const nsRect& aBounds) : ExtraData(aBounds) {
658 }
659 nsFloatCacheList mFloats;
660 };
662 protected:
663 nscoord mAscent; // see |SetAscent| / |GetAscent|
664 union {
665 uint32_t mAllFlags;
666 FlagBits mFlags;
667 };
669 union {
670 ExtraData* mData;
671 ExtraBlockData* mBlockData;
672 ExtraInlineData* mInlineData;
673 };
675 void Cleanup();
676 void MaybeFreeData();
677 };
679 /**
680 * A linked list type where the items in the list must inherit from
681 * a link type to fuse allocations.
682 *
683 * API heavily based on the |list| class in the C++ standard.
684 */
686 class nsLineList_iterator {
687 public:
688 friend class nsLineList;
689 friend class nsLineList_reverse_iterator;
690 friend class nsLineList_const_iterator;
691 friend class nsLineList_const_reverse_iterator;
693 typedef nsLineList_iterator iterator_self_type;
694 typedef nsLineList_reverse_iterator iterator_reverse_type;
696 typedef nsLineBox& reference;
697 typedef const nsLineBox& const_reference;
699 typedef nsLineBox* pointer;
700 typedef const nsLineBox* const_pointer;
702 typedef uint32_t size_type;
703 typedef int32_t difference_type;
705 typedef nsLineLink link_type;
707 #ifdef DEBUG
708 nsLineList_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
709 #else
710 // Auto generated default constructor OK.
711 #endif
712 // Auto generated copy-constructor OK.
714 inline iterator_self_type&
715 operator=(const iterator_self_type& aOther);
716 inline iterator_self_type&
717 operator=(const iterator_reverse_type& aOther);
719 iterator_self_type& operator++()
720 {
721 mCurrent = mCurrent->_mNext;
722 return *this;
723 }
725 iterator_self_type operator++(int)
726 {
727 iterator_self_type rv(*this);
728 mCurrent = mCurrent->_mNext;
729 return rv;
730 }
732 iterator_self_type& operator--()
733 {
734 mCurrent = mCurrent->_mPrev;
735 return *this;
736 }
738 iterator_self_type operator--(int)
739 {
740 iterator_self_type rv(*this);
741 mCurrent = mCurrent->_mPrev;
742 return rv;
743 }
745 reference operator*()
746 {
747 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
748 return *static_cast<pointer>(mCurrent);
749 }
751 pointer operator->()
752 {
753 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
754 return static_cast<pointer>(mCurrent);
755 }
757 pointer get()
758 {
759 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
760 return static_cast<pointer>(mCurrent);
761 }
763 operator pointer()
764 {
765 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
766 return static_cast<pointer>(mCurrent);
767 }
769 const_reference operator*() const
770 {
771 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
772 return *static_cast<const_pointer>(mCurrent);
773 }
775 const_pointer operator->() const
776 {
777 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
778 return static_cast<const_pointer>(mCurrent);
779 }
781 #ifndef __MWERKS__
782 operator const_pointer() const
783 {
784 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
785 return static_cast<const_pointer>(mCurrent);
786 }
787 #endif /* !__MWERKS__ */
789 iterator_self_type next()
790 {
791 iterator_self_type copy(*this);
792 return ++copy;
793 }
795 const iterator_self_type next() const
796 {
797 iterator_self_type copy(*this);
798 return ++copy;
799 }
801 iterator_self_type prev()
802 {
803 iterator_self_type copy(*this);
804 return --copy;
805 }
807 const iterator_self_type prev() const
808 {
809 iterator_self_type copy(*this);
810 return --copy;
811 }
813 // Passing by value rather than by reference and reference to const
814 // to keep AIX happy.
815 bool operator==(const iterator_self_type aOther) const
816 {
817 NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists");
818 return mCurrent == aOther.mCurrent;
819 }
820 bool operator!=(const iterator_self_type aOther) const
821 {
822 NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists");
823 return mCurrent != aOther.mCurrent;
824 }
825 bool operator==(const iterator_self_type aOther)
826 {
827 NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists");
828 return mCurrent == aOther.mCurrent;
829 }
830 bool operator!=(const iterator_self_type aOther)
831 {
832 NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists");
833 return mCurrent != aOther.mCurrent;
834 }
836 private:
837 link_type *mCurrent;
838 #ifdef DEBUG
839 link_type *mListLink; // the list's link, i.e., the end
840 #endif
841 };
843 class nsLineList_reverse_iterator {
845 public:
847 friend class nsLineList;
848 friend class nsLineList_iterator;
849 friend class nsLineList_const_iterator;
850 friend class nsLineList_const_reverse_iterator;
852 typedef nsLineList_reverse_iterator iterator_self_type;
853 typedef nsLineList_iterator iterator_reverse_type;
855 typedef nsLineBox& reference;
856 typedef const nsLineBox& const_reference;
858 typedef nsLineBox* pointer;
859 typedef const nsLineBox* const_pointer;
861 typedef uint32_t size_type;
862 typedef int32_t difference_type;
864 typedef nsLineLink link_type;
866 #ifdef DEBUG
867 nsLineList_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
868 #else
869 // Auto generated default constructor OK.
870 #endif
871 // Auto generated copy-constructor OK.
873 inline iterator_self_type&
874 operator=(const iterator_reverse_type& aOther);
875 inline iterator_self_type&
876 operator=(const iterator_self_type& aOther);
878 iterator_self_type& operator++()
879 {
880 mCurrent = mCurrent->_mPrev;
881 return *this;
882 }
884 iterator_self_type operator++(int)
885 {
886 iterator_self_type rv(*this);
887 mCurrent = mCurrent->_mPrev;
888 return rv;
889 }
891 iterator_self_type& operator--()
892 {
893 mCurrent = mCurrent->_mNext;
894 return *this;
895 }
897 iterator_self_type operator--(int)
898 {
899 iterator_self_type rv(*this);
900 mCurrent = mCurrent->_mNext;
901 return rv;
902 }
904 reference operator*()
905 {
906 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
907 return *static_cast<pointer>(mCurrent);
908 }
910 pointer operator->()
911 {
912 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
913 return static_cast<pointer>(mCurrent);
914 }
916 pointer get()
917 {
918 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
919 return static_cast<pointer>(mCurrent);
920 }
922 operator pointer()
923 {
924 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
925 return static_cast<pointer>(mCurrent);
926 }
928 const_reference operator*() const
929 {
930 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
931 return *static_cast<const_pointer>(mCurrent);
932 }
934 const_pointer operator->() const
935 {
936 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
937 return static_cast<const_pointer>(mCurrent);
938 }
940 #ifndef __MWERKS__
941 operator const_pointer() const
942 {
943 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
944 return static_cast<const_pointer>(mCurrent);
945 }
946 #endif /* !__MWERKS__ */
948 // Passing by value rather than by reference and reference to const
949 // to keep AIX happy.
950 bool operator==(const iterator_self_type aOther) const
951 {
952 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
953 return mCurrent == aOther.mCurrent;
954 }
955 bool operator!=(const iterator_self_type aOther) const
956 {
957 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
958 return mCurrent != aOther.mCurrent;
959 }
960 bool operator==(const iterator_self_type aOther)
961 {
962 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
963 return mCurrent == aOther.mCurrent;
964 }
965 bool operator!=(const iterator_self_type aOther)
966 {
967 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
968 return mCurrent != aOther.mCurrent;
969 }
971 private:
972 link_type *mCurrent;
973 #ifdef DEBUG
974 link_type *mListLink; // the list's link, i.e., the end
975 #endif
976 };
978 class nsLineList_const_iterator {
979 public:
981 friend class nsLineList;
982 friend class nsLineList_iterator;
983 friend class nsLineList_reverse_iterator;
984 friend class nsLineList_const_reverse_iterator;
986 typedef nsLineList_const_iterator iterator_self_type;
987 typedef nsLineList_const_reverse_iterator iterator_reverse_type;
988 typedef nsLineList_iterator iterator_nonconst_type;
989 typedef nsLineList_reverse_iterator iterator_nonconst_reverse_type;
991 typedef nsLineBox& reference;
992 typedef const nsLineBox& const_reference;
994 typedef nsLineBox* pointer;
995 typedef const nsLineBox* const_pointer;
997 typedef uint32_t size_type;
998 typedef int32_t difference_type;
1000 typedef nsLineLink link_type;
1002 #ifdef DEBUG
1003 nsLineList_const_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
1004 #else
1005 // Auto generated default constructor OK.
1006 #endif
1007 // Auto generated copy-constructor OK.
1009 inline iterator_self_type&
1010 operator=(const iterator_nonconst_type& aOther);
1011 inline iterator_self_type&
1012 operator=(const iterator_nonconst_reverse_type& aOther);
1013 inline iterator_self_type&
1014 operator=(const iterator_self_type& aOther);
1015 inline iterator_self_type&
1016 operator=(const iterator_reverse_type& aOther);
1018 iterator_self_type& operator++()
1019 {
1020 mCurrent = mCurrent->_mNext;
1021 return *this;
1022 }
1024 iterator_self_type operator++(int)
1025 {
1026 iterator_self_type rv(*this);
1027 mCurrent = mCurrent->_mNext;
1028 return rv;
1029 }
1031 iterator_self_type& operator--()
1032 {
1033 mCurrent = mCurrent->_mPrev;
1034 return *this;
1035 }
1037 iterator_self_type operator--(int)
1038 {
1039 iterator_self_type rv(*this);
1040 mCurrent = mCurrent->_mPrev;
1041 return rv;
1042 }
1044 const_reference operator*() const
1045 {
1046 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1047 return *static_cast<const_pointer>(mCurrent);
1048 }
1050 const_pointer operator->() const
1051 {
1052 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1053 return static_cast<const_pointer>(mCurrent);
1054 }
1056 const_pointer get() const
1057 {
1058 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1059 return static_cast<const_pointer>(mCurrent);
1060 }
1062 #ifndef __MWERKS__
1063 operator const_pointer() const
1064 {
1065 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1066 return static_cast<const_pointer>(mCurrent);
1067 }
1068 #endif /* !__MWERKS__ */
1070 const iterator_self_type next() const
1071 {
1072 iterator_self_type copy(*this);
1073 return ++copy;
1074 }
1076 const iterator_self_type prev() const
1077 {
1078 iterator_self_type copy(*this);
1079 return --copy;
1080 }
1082 // Passing by value rather than by reference and reference to const
1083 // to keep AIX happy.
1084 bool operator==(const iterator_self_type aOther) const
1085 {
1086 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1087 return mCurrent == aOther.mCurrent;
1088 }
1089 bool operator!=(const iterator_self_type aOther) const
1090 {
1091 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1092 return mCurrent != aOther.mCurrent;
1093 }
1094 bool operator==(const iterator_self_type aOther)
1095 {
1096 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1097 return mCurrent == aOther.mCurrent;
1098 }
1099 bool operator!=(const iterator_self_type aOther)
1100 {
1101 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1102 return mCurrent != aOther.mCurrent;
1103 }
1105 private:
1106 const link_type *mCurrent;
1107 #ifdef DEBUG
1108 const link_type *mListLink; // the list's link, i.e., the end
1109 #endif
1110 };
1112 class nsLineList_const_reverse_iterator {
1113 public:
1115 friend class nsLineList;
1116 friend class nsLineList_iterator;
1117 friend class nsLineList_reverse_iterator;
1118 friend class nsLineList_const_iterator;
1120 typedef nsLineList_const_reverse_iterator iterator_self_type;
1121 typedef nsLineList_const_iterator iterator_reverse_type;
1122 typedef nsLineList_iterator iterator_nonconst_reverse_type;
1123 typedef nsLineList_reverse_iterator iterator_nonconst_type;
1125 typedef nsLineBox& reference;
1126 typedef const nsLineBox& const_reference;
1128 typedef nsLineBox* pointer;
1129 typedef const nsLineBox* const_pointer;
1131 typedef uint32_t size_type;
1132 typedef int32_t difference_type;
1134 typedef nsLineLink link_type;
1136 #ifdef DEBUG
1137 nsLineList_const_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
1138 #else
1139 // Auto generated default constructor OK.
1140 #endif
1141 // Auto generated copy-constructor OK.
1143 inline iterator_self_type&
1144 operator=(const iterator_nonconst_type& aOther);
1145 inline iterator_self_type&
1146 operator=(const iterator_nonconst_reverse_type& aOther);
1147 inline iterator_self_type&
1148 operator=(const iterator_self_type& aOther);
1149 inline iterator_self_type&
1150 operator=(const iterator_reverse_type& aOther);
1152 iterator_self_type& operator++()
1153 {
1154 mCurrent = mCurrent->_mPrev;
1155 return *this;
1156 }
1158 iterator_self_type operator++(int)
1159 {
1160 iterator_self_type rv(*this);
1161 mCurrent = mCurrent->_mPrev;
1162 return rv;
1163 }
1165 iterator_self_type& operator--()
1166 {
1167 mCurrent = mCurrent->_mNext;
1168 return *this;
1169 }
1171 iterator_self_type operator--(int)
1172 {
1173 iterator_self_type rv(*this);
1174 mCurrent = mCurrent->_mNext;
1175 return rv;
1176 }
1178 const_reference operator*() const
1179 {
1180 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1181 return *static_cast<const_pointer>(mCurrent);
1182 }
1184 const_pointer operator->() const
1185 {
1186 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1187 return static_cast<const_pointer>(mCurrent);
1188 }
1190 const_pointer get() const
1191 {
1192 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1193 return static_cast<const_pointer>(mCurrent);
1194 }
1196 #ifndef __MWERKS__
1197 operator const_pointer() const
1198 {
1199 NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end");
1200 return static_cast<const_pointer>(mCurrent);
1201 }
1202 #endif /* !__MWERKS__ */
1204 // Passing by value rather than by reference and reference to const
1205 // to keep AIX happy.
1206 bool operator==(const iterator_self_type aOther) const
1207 {
1208 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1209 return mCurrent == aOther.mCurrent;
1210 }
1211 bool operator!=(const iterator_self_type aOther) const
1212 {
1213 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1214 return mCurrent != aOther.mCurrent;
1215 }
1216 bool operator==(const iterator_self_type aOther)
1217 {
1218 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1219 return mCurrent == aOther.mCurrent;
1220 }
1221 bool operator!=(const iterator_self_type aOther)
1222 {
1223 NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1224 return mCurrent != aOther.mCurrent;
1225 }
1227 //private:
1228 const link_type *mCurrent;
1229 #ifdef DEBUG
1230 const link_type *mListLink; // the list's link, i.e., the end
1231 #endif
1232 };
1234 class nsLineList {
1236 public:
1238 friend class nsLineList_iterator;
1239 friend class nsLineList_reverse_iterator;
1240 friend class nsLineList_const_iterator;
1241 friend class nsLineList_const_reverse_iterator;
1243 typedef uint32_t size_type;
1244 typedef int32_t difference_type;
1246 typedef nsLineLink link_type;
1248 private:
1249 link_type mLink;
1251 public:
1252 typedef nsLineList self_type;
1254 typedef nsLineBox& reference;
1255 typedef const nsLineBox& const_reference;
1257 typedef nsLineBox* pointer;
1258 typedef const nsLineBox* const_pointer;
1260 typedef nsLineList_iterator iterator;
1261 typedef nsLineList_reverse_iterator reverse_iterator;
1262 typedef nsLineList_const_iterator const_iterator;
1263 typedef nsLineList_const_reverse_iterator const_reverse_iterator;
1265 nsLineList()
1266 {
1267 MOZ_COUNT_CTOR(nsLineList);
1268 clear();
1269 }
1271 ~nsLineList()
1272 {
1273 MOZ_COUNT_DTOR(nsLineList);
1274 }
1276 const_iterator begin() const
1277 {
1278 const_iterator rv;
1279 rv.mCurrent = mLink._mNext;
1280 #ifdef DEBUG
1281 rv.mListLink = &mLink;
1282 #endif
1283 return rv;
1284 }
1286 iterator begin()
1287 {
1288 iterator rv;
1289 rv.mCurrent = mLink._mNext;
1290 #ifdef DEBUG
1291 rv.mListLink = &mLink;
1292 #endif
1293 return rv;
1294 }
1296 iterator begin(nsLineBox* aLine)
1297 {
1298 iterator rv;
1299 rv.mCurrent = aLine;
1300 #ifdef DEBUG
1301 rv.mListLink = &mLink;
1302 #endif
1303 return rv;
1304 }
1306 const_iterator end() const
1307 {
1308 const_iterator rv;
1309 rv.mCurrent = &mLink;
1310 #ifdef DEBUG
1311 rv.mListLink = &mLink;
1312 #endif
1313 return rv;
1314 }
1316 iterator end()
1317 {
1318 iterator rv;
1319 rv.mCurrent = &mLink;
1320 #ifdef DEBUG
1321 rv.mListLink = &mLink;
1322 #endif
1323 return rv;
1324 }
1326 const_reverse_iterator rbegin() const
1327 {
1328 const_reverse_iterator rv;
1329 rv.mCurrent = mLink._mPrev;
1330 #ifdef DEBUG
1331 rv.mListLink = &mLink;
1332 #endif
1333 return rv;
1334 }
1336 reverse_iterator rbegin()
1337 {
1338 reverse_iterator rv;
1339 rv.mCurrent = mLink._mPrev;
1340 #ifdef DEBUG
1341 rv.mListLink = &mLink;
1342 #endif
1343 return rv;
1344 }
1346 reverse_iterator rbegin(nsLineBox* aLine)
1347 {
1348 reverse_iterator rv;
1349 rv.mCurrent = aLine;
1350 #ifdef DEBUG
1351 rv.mListLink = &mLink;
1352 #endif
1353 return rv;
1354 }
1356 const_reverse_iterator rend() const
1357 {
1358 const_reverse_iterator rv;
1359 rv.mCurrent = &mLink;
1360 #ifdef DEBUG
1361 rv.mListLink = &mLink;
1362 #endif
1363 return rv;
1364 }
1366 reverse_iterator rend()
1367 {
1368 reverse_iterator rv;
1369 rv.mCurrent = &mLink;
1370 #ifdef DEBUG
1371 rv.mListLink = &mLink;
1372 #endif
1373 return rv;
1374 }
1376 bool empty() const
1377 {
1378 return mLink._mNext == &mLink;
1379 }
1381 // NOTE: O(N).
1382 size_type size() const
1383 {
1384 size_type count = 0;
1385 for (const link_type *cur = mLink._mNext;
1386 cur != &mLink;
1387 cur = cur->_mNext)
1388 {
1389 ++count;
1390 }
1391 return count;
1392 }
1394 pointer front()
1395 {
1396 NS_ASSERTION(!empty(), "no element to return");
1397 return static_cast<pointer>(mLink._mNext);
1398 }
1400 const_pointer front() const
1401 {
1402 NS_ASSERTION(!empty(), "no element to return");
1403 return static_cast<const_pointer>(mLink._mNext);
1404 }
1406 pointer back()
1407 {
1408 NS_ASSERTION(!empty(), "no element to return");
1409 return static_cast<pointer>(mLink._mPrev);
1410 }
1412 const_pointer back() const
1413 {
1414 NS_ASSERTION(!empty(), "no element to return");
1415 return static_cast<const_pointer>(mLink._mPrev);
1416 }
1418 void push_front(pointer aNew)
1419 {
1420 aNew->_mNext = mLink._mNext;
1421 mLink._mNext->_mPrev = aNew;
1422 aNew->_mPrev = &mLink;
1423 mLink._mNext = aNew;
1424 }
1426 void pop_front()
1427 // NOTE: leaves dangling next/prev pointers
1428 {
1429 NS_ASSERTION(!empty(), "no element to pop");
1430 link_type *newFirst = mLink._mNext->_mNext;
1431 newFirst->_mPrev = &mLink;
1432 // mLink._mNext->_mNext = nullptr;
1433 // mLink._mNext->_mPrev = nullptr;
1434 mLink._mNext = newFirst;
1435 }
1437 void push_back(pointer aNew)
1438 {
1439 aNew->_mPrev = mLink._mPrev;
1440 mLink._mPrev->_mNext = aNew;
1441 aNew->_mNext = &mLink;
1442 mLink._mPrev = aNew;
1443 }
1445 void pop_back()
1446 // NOTE: leaves dangling next/prev pointers
1447 {
1448 NS_ASSERTION(!empty(), "no element to pop");
1449 link_type *newLast = mLink._mPrev->_mPrev;
1450 newLast->_mNext = &mLink;
1451 // mLink._mPrev->_mPrev = nullptr;
1452 // mLink._mPrev->_mNext = nullptr;
1453 mLink._mPrev = newLast;
1454 }
1456 // inserts x before position
1457 iterator before_insert(iterator position, pointer x)
1458 {
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 }
1467 // inserts x after position
1468 iterator after_insert(iterator position, pointer x)
1469 {
1470 // use |mCurrent| to prevent DEBUG_PASS_END assertions
1471 x->_mNext = position.mCurrent->_mNext;
1472 x->_mPrev = position.mCurrent;
1473 position.mCurrent->_mNext->_mPrev = x;
1474 position.mCurrent->_mNext = x;
1475 return ++position;
1476 }
1478 // returns iterator pointing to after the element
1479 iterator erase(iterator position)
1480 // NOTE: leaves dangling next/prev pointers
1481 {
1482 position->_mPrev->_mNext = position->_mNext;
1483 position->_mNext->_mPrev = position->_mPrev;
1484 return ++position;
1485 }
1487 void swap(self_type& y)
1488 {
1489 link_type tmp(y.mLink);
1490 y.mLink = mLink;
1491 mLink = tmp;
1493 if (!empty()) {
1494 mLink._mNext->_mPrev = &mLink;
1495 mLink._mPrev->_mNext = &mLink;
1496 }
1498 if (!y.empty()) {
1499 y.mLink._mNext->_mPrev = &y.mLink;
1500 y.mLink._mPrev->_mNext = &y.mLink;
1501 }
1502 }
1504 void clear()
1505 // NOTE: leaves dangling next/prev pointers
1506 {
1507 mLink._mNext = &mLink;
1508 mLink._mPrev = &mLink;
1509 }
1511 // inserts the conts of x before position and makes x empty
1512 void splice(iterator position, self_type& x)
1513 {
1514 // use |mCurrent| to prevent DEBUG_PASS_END assertions
1515 position.mCurrent->_mPrev->_mNext = x.mLink._mNext;
1516 x.mLink._mNext->_mPrev = position.mCurrent->_mPrev;
1517 x.mLink._mPrev->_mNext = position.mCurrent;
1518 position.mCurrent->_mPrev = x.mLink._mPrev;
1519 x.clear();
1520 }
1522 // Inserts element *i from list x before position and removes
1523 // it from x.
1524 void splice(iterator position, self_type& x, iterator i)
1525 {
1526 NS_ASSERTION(!x.empty(), "Can't insert from empty list.");
1527 NS_ASSERTION(position != i && position.mCurrent != i->_mNext,
1528 "We don't check for this case.");
1530 // remove from |x|
1531 i->_mPrev->_mNext = i->_mNext;
1532 i->_mNext->_mPrev = i->_mPrev;
1534 // use |mCurrent| to prevent DEBUG_PASS_END assertions
1535 // link into |this|, before-side
1536 i->_mPrev = position.mCurrent->_mPrev;
1537 position.mCurrent->_mPrev->_mNext = i.get();
1539 // link into |this|, after-side
1540 i->_mNext = position.mCurrent;
1541 position.mCurrent->_mPrev = i.get();
1542 }
1544 // Inserts elements in [|first|, |last|), which are in |x|,
1545 // into |this| before |position| and removes them from |x|.
1546 void splice(iterator position, self_type& x, iterator first,
1547 iterator last)
1548 {
1549 NS_ASSERTION(!x.empty(), "Can't insert from empty list.");
1551 if (first == last)
1552 return;
1554 --last; // so we now want to move [first, last]
1555 // remove from |x|
1556 first->_mPrev->_mNext = last->_mNext;
1557 last->_mNext->_mPrev = first->_mPrev;
1559 // use |mCurrent| to prevent DEBUG_PASS_END assertions
1560 // link into |this|, before-side
1561 first->_mPrev = position.mCurrent->_mPrev;
1562 position.mCurrent->_mPrev->_mNext = first.get();
1564 // link into |this|, after-side
1565 last->_mNext = position.mCurrent;
1566 position.mCurrent->_mPrev = last.get();
1567 }
1569 };
1572 // Many of these implementations of operator= don't work yet. I don't
1573 // know why.
1575 #ifdef DEBUG
1577 // NOTE: ASSIGN_FROM is meant to be used *only* as the entire body
1578 // of a function and therefore lacks PR_{BEGIN,END}_MACRO
1579 #define ASSIGN_FROM(other_) \
1580 mCurrent = other_.mCurrent; \
1581 mListLink = other_.mListLink; \
1582 return *this;
1584 #else /* !NS_LINELIST_DEBUG_PASS_END */
1586 #define ASSIGN_FROM(other_) \
1587 mCurrent = other_.mCurrent; \
1588 return *this;
1590 #endif /* !NS_LINELIST_DEBUG_PASS_END */
1592 inline
1593 nsLineList_iterator&
1594 nsLineList_iterator::operator=(const nsLineList_iterator& aOther)
1595 {
1596 ASSIGN_FROM(aOther)
1597 }
1599 inline
1600 nsLineList_iterator&
1601 nsLineList_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1602 {
1603 ASSIGN_FROM(aOther)
1604 }
1606 inline
1607 nsLineList_reverse_iterator&
1608 nsLineList_reverse_iterator::operator=(const nsLineList_iterator& aOther)
1609 {
1610 ASSIGN_FROM(aOther)
1611 }
1613 inline
1614 nsLineList_reverse_iterator&
1615 nsLineList_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1616 {
1617 ASSIGN_FROM(aOther)
1618 }
1620 inline
1621 nsLineList_const_iterator&
1622 nsLineList_const_iterator::operator=(const nsLineList_iterator& aOther)
1623 {
1624 ASSIGN_FROM(aOther)
1625 }
1627 inline
1628 nsLineList_const_iterator&
1629 nsLineList_const_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1630 {
1631 ASSIGN_FROM(aOther)
1632 }
1634 inline
1635 nsLineList_const_iterator&
1636 nsLineList_const_iterator::operator=(const nsLineList_const_iterator& aOther)
1637 {
1638 ASSIGN_FROM(aOther)
1639 }
1641 inline
1642 nsLineList_const_iterator&
1643 nsLineList_const_iterator::operator=(const nsLineList_const_reverse_iterator& aOther)
1644 {
1645 ASSIGN_FROM(aOther)
1646 }
1648 inline
1649 nsLineList_const_reverse_iterator&
1650 nsLineList_const_reverse_iterator::operator=(const nsLineList_iterator& aOther)
1651 {
1652 ASSIGN_FROM(aOther)
1653 }
1655 inline
1656 nsLineList_const_reverse_iterator&
1657 nsLineList_const_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1658 {
1659 ASSIGN_FROM(aOther)
1660 }
1662 inline
1663 nsLineList_const_reverse_iterator&
1664 nsLineList_const_reverse_iterator::operator=(const nsLineList_const_iterator& aOther)
1665 {
1666 ASSIGN_FROM(aOther)
1667 }
1669 inline
1670 nsLineList_const_reverse_iterator&
1671 nsLineList_const_reverse_iterator::operator=(const nsLineList_const_reverse_iterator& aOther)
1672 {
1673 ASSIGN_FROM(aOther)
1674 }
1677 //----------------------------------------------------------------------
1679 class nsLineIterator MOZ_FINAL : public nsILineIterator
1680 {
1681 public:
1682 nsLineIterator();
1683 ~nsLineIterator();
1685 virtual void DisposeLineIterator() MOZ_OVERRIDE;
1687 virtual int32_t GetNumLines() MOZ_OVERRIDE;
1688 virtual bool GetDirection() MOZ_OVERRIDE;
1689 NS_IMETHOD GetLine(int32_t aLineNumber,
1690 nsIFrame** aFirstFrameOnLine,
1691 int32_t* aNumFramesOnLine,
1692 nsRect& aLineBounds,
1693 uint32_t* aLineFlags) MOZ_OVERRIDE;
1694 virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) MOZ_OVERRIDE;
1695 NS_IMETHOD FindFrameAt(int32_t aLineNumber,
1696 nscoord aX,
1697 nsIFrame** aFrameFound,
1698 bool* aXIsBeforeFirstFrame,
1699 bool* aXIsAfterLastFrame) MOZ_OVERRIDE;
1701 NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) MOZ_OVERRIDE;
1702 NS_IMETHOD CheckLineOrder(int32_t aLine,
1703 bool *aIsReordered,
1704 nsIFrame **aFirstVisual,
1705 nsIFrame **aLastVisual) MOZ_OVERRIDE;
1706 nsresult Init(nsLineList& aLines, bool aRightToLeft);
1708 private:
1709 nsLineBox* PrevLine() {
1710 if (0 == mIndex) {
1711 return nullptr;
1712 }
1713 return mLines[--mIndex];
1714 }
1716 nsLineBox* NextLine() {
1717 if (mIndex >= mNumLines - 1) {
1718 return nullptr;
1719 }
1720 return mLines[++mIndex];
1721 }
1723 nsLineBox* LineAt(int32_t aIndex) {
1724 if ((aIndex < 0) || (aIndex >= mNumLines)) {
1725 return nullptr;
1726 }
1727 return mLines[aIndex];
1728 }
1730 nsLineBox** mLines;
1731 int32_t mIndex;
1732 int32_t mNumLines;
1733 bool mRightToLeft;
1734 };
1736 #endif /* nsLineBox_h___ */