michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // vim:cindent:ts=2:et:sw=2: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* representation of one line within a block frame, a CSS line box */ michael@0: michael@0: #ifndef nsLineBox_h___ michael@0: #define nsLineBox_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Likely.h" michael@0: michael@0: #include "nsILineIterator.h" michael@0: #include "nsIFrame.h" michael@0: #include michael@0: michael@0: class nsLineBox; michael@0: class nsFloatCache; michael@0: class nsFloatCacheList; michael@0: class nsFloatCacheFreeList; michael@0: michael@0: // State cached after reflowing a float. This state is used during michael@0: // incremental reflow when we avoid reflowing a float. michael@0: class nsFloatCache { michael@0: public: michael@0: nsFloatCache(); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: ~nsFloatCache(); michael@0: #else michael@0: ~nsFloatCache() { } michael@0: #endif michael@0: michael@0: nsFloatCache* Next() const { return mNext; } michael@0: michael@0: nsIFrame* mFloat; // floating frame michael@0: michael@0: protected: michael@0: nsFloatCache* mNext; michael@0: michael@0: friend class nsFloatCacheList; michael@0: friend class nsFloatCacheFreeList; michael@0: }; michael@0: michael@0: //---------------------------------------- michael@0: michael@0: class nsFloatCacheList { michael@0: public: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: nsFloatCacheList(); michael@0: #else michael@0: nsFloatCacheList() : mHead(nullptr) { } michael@0: #endif michael@0: ~nsFloatCacheList(); michael@0: michael@0: bool IsEmpty() const { michael@0: return nullptr == mHead; michael@0: } michael@0: michael@0: bool NotEmpty() const { michael@0: return nullptr != mHead; michael@0: } michael@0: michael@0: nsFloatCache* Head() const { michael@0: return mHead; michael@0: } michael@0: michael@0: nsFloatCache* Tail() const; michael@0: michael@0: void DeleteAll(); michael@0: michael@0: nsFloatCache* Find(nsIFrame* aOutOfFlowFrame); michael@0: michael@0: // Remove a nsFloatCache from this list. Deleting this nsFloatCache michael@0: // becomes the caller's responsibility. michael@0: void Remove(nsFloatCache* aElement) { RemoveAndReturnPrev(aElement); } michael@0: michael@0: // Steal away aList's nsFloatCache objects and put them in this michael@0: // list. aList must not be empty. michael@0: void Append(nsFloatCacheFreeList& aList); michael@0: michael@0: protected: michael@0: nsFloatCache* mHead; michael@0: michael@0: // Remove a nsFloatCache from this list. Deleting this nsFloatCache michael@0: // becomes the caller's responsibility. Returns the nsFloatCache that was michael@0: // before aElement, or nullptr if aElement was the first. michael@0: nsFloatCache* RemoveAndReturnPrev(nsFloatCache* aElement); michael@0: michael@0: friend class nsFloatCacheFreeList; michael@0: }; michael@0: michael@0: //--------------------------------------- michael@0: // Like nsFloatCacheList, but with fast access to the tail michael@0: michael@0: class nsFloatCacheFreeList : private nsFloatCacheList { michael@0: public: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: nsFloatCacheFreeList(); michael@0: ~nsFloatCacheFreeList(); michael@0: #else michael@0: nsFloatCacheFreeList() : mTail(nullptr) { } michael@0: ~nsFloatCacheFreeList() { } michael@0: #endif michael@0: michael@0: // Reimplement trivial functions michael@0: bool IsEmpty() const { michael@0: return nullptr == mHead; michael@0: } michael@0: michael@0: nsFloatCache* Head() const { michael@0: return mHead; michael@0: } michael@0: michael@0: nsFloatCache* Tail() const { michael@0: return mTail; michael@0: } michael@0: michael@0: bool NotEmpty() const { michael@0: return nullptr != mHead; michael@0: } michael@0: michael@0: void DeleteAll(); michael@0: michael@0: // Steal away aList's nsFloatCache objects and put them on this michael@0: // free-list. aList must not be empty. michael@0: void Append(nsFloatCacheList& aList); michael@0: michael@0: void Append(nsFloatCache* aFloatCache); michael@0: michael@0: void Remove(nsFloatCache* aElement); michael@0: michael@0: // Remove an nsFloatCache object from this list and return it, or create michael@0: // a new one if this one is empty; Set its mFloat to aFloat. michael@0: nsFloatCache* Alloc(nsIFrame* aFloat); michael@0: michael@0: protected: michael@0: nsFloatCache* mTail; michael@0: michael@0: friend class nsFloatCacheList; michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: #define LINE_MAX_BREAK_TYPE ((1 << 4) - 1) michael@0: #define LINE_MAX_CHILD_COUNT INT32_MAX michael@0: michael@0: /** michael@0: * Function to create a line box and initialize it with a single frame. michael@0: * The allocation is infallible. michael@0: * If the frame was moved from another line then you're responsible michael@0: * for notifying that line using NoteFrameRemoved(). Alternatively, michael@0: * it's better to use the next function that does that for you in an michael@0: * optimal way. michael@0: */ michael@0: nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, michael@0: bool aIsBlock); michael@0: /** michael@0: * Function to create a line box and initialize it with aCount frames michael@0: * that are currently on aFromLine. The allocation is infallible. michael@0: */ michael@0: nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine, michael@0: nsIFrame* aFrame, int32_t aCount); michael@0: michael@0: class nsLineList; michael@0: michael@0: // don't use the following names outside of this file. Instead, use michael@0: // nsLineList::iterator, etc. These are just here to allow them to michael@0: // be specified as parameters to methods of nsLineBox. michael@0: class nsLineList_iterator; michael@0: class nsLineList_const_iterator; michael@0: class nsLineList_reverse_iterator; michael@0: class nsLineList_const_reverse_iterator; michael@0: michael@0: /** michael@0: * Users must have the class that is to be part of the list inherit michael@0: * from nsLineLink. If they want to be efficient, it should be the michael@0: * first base class. (This was originally nsCLink in a templatized michael@0: * nsCList, but it's still useful separately.) michael@0: */ michael@0: michael@0: class nsLineLink { michael@0: michael@0: public: michael@0: friend class nsLineList; michael@0: friend class nsLineList_iterator; michael@0: friend class nsLineList_reverse_iterator; michael@0: friend class nsLineList_const_iterator; michael@0: friend class nsLineList_const_reverse_iterator; michael@0: michael@0: private: michael@0: nsLineLink *_mNext; // or head michael@0: nsLineLink *_mPrev; // or tail michael@0: michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * The nsLineBox class represents a horizontal line of frames. It contains michael@0: * enough state to support incremental reflow of the frames, event handling michael@0: * for the frames, and rendering of the frames. michael@0: */ michael@0: class nsLineBox MOZ_FINAL : public nsLineLink { michael@0: private: michael@0: nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock); michael@0: ~nsLineBox(); michael@0: michael@0: // Overloaded new operator. Uses an arena (which comes from the presShell) michael@0: // to perform the allocation. michael@0: void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW; michael@0: void operator delete(void* aPtr, size_t sz) MOZ_DELETE; michael@0: michael@0: public: michael@0: // Use these functions to allocate and destroy line boxes michael@0: friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, michael@0: bool aIsBlock); michael@0: friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine, michael@0: nsIFrame* aFrame, int32_t aCount); michael@0: void Destroy(nsIPresShell* aPresShell); michael@0: michael@0: // mBlock bit michael@0: bool IsBlock() const { michael@0: return mFlags.mBlock; michael@0: } michael@0: bool IsInline() const { michael@0: return 0 == mFlags.mBlock; michael@0: } michael@0: michael@0: // mDirty bit michael@0: void MarkDirty() { michael@0: mFlags.mDirty = 1; michael@0: } michael@0: void ClearDirty() { michael@0: mFlags.mDirty = 0; michael@0: } michael@0: bool IsDirty() const { michael@0: return mFlags.mDirty; michael@0: } michael@0: michael@0: // mPreviousMarginDirty bit michael@0: void MarkPreviousMarginDirty() { michael@0: mFlags.mPreviousMarginDirty = 1; michael@0: } michael@0: void ClearPreviousMarginDirty() { michael@0: mFlags.mPreviousMarginDirty = 0; michael@0: } michael@0: bool IsPreviousMarginDirty() const { michael@0: return mFlags.mPreviousMarginDirty; michael@0: } michael@0: michael@0: // mHasClearance bit michael@0: void SetHasClearance() { michael@0: mFlags.mHasClearance = 1; michael@0: } michael@0: void ClearHasClearance() { michael@0: mFlags.mHasClearance = 0; michael@0: } michael@0: bool HasClearance() const { michael@0: return mFlags.mHasClearance; michael@0: } michael@0: michael@0: // mImpactedByFloat bit michael@0: void SetLineIsImpactedByFloat(bool aValue) { michael@0: mFlags.mImpactedByFloat = aValue; michael@0: } michael@0: bool IsImpactedByFloat() const { michael@0: return mFlags.mImpactedByFloat; michael@0: } michael@0: michael@0: // mLineWrapped bit michael@0: void SetLineWrapped(bool aOn) { michael@0: mFlags.mLineWrapped = aOn; michael@0: } michael@0: bool IsLineWrapped() const { michael@0: return mFlags.mLineWrapped; michael@0: } michael@0: michael@0: // mInvalidateTextRuns bit michael@0: void SetInvalidateTextRuns(bool aOn) { michael@0: mFlags.mInvalidateTextRuns = aOn; michael@0: } michael@0: bool GetInvalidateTextRuns() const { michael@0: return mFlags.mInvalidateTextRuns; michael@0: } michael@0: michael@0: // mResizeReflowOptimizationDisabled bit michael@0: void DisableResizeReflowOptimization() { michael@0: mFlags.mResizeReflowOptimizationDisabled = true; michael@0: } michael@0: void EnableResizeReflowOptimization() { michael@0: mFlags.mResizeReflowOptimizationDisabled = false; michael@0: } michael@0: bool ResizeReflowOptimizationDisabled() const { michael@0: return mFlags.mResizeReflowOptimizationDisabled; michael@0: } michael@0: michael@0: // mHasBullet bit michael@0: void SetHasBullet() { michael@0: mFlags.mHasBullet = true; michael@0: InvalidateCachedIsEmpty(); michael@0: } michael@0: void ClearHasBullet() { michael@0: mFlags.mHasBullet = false; michael@0: InvalidateCachedIsEmpty(); michael@0: } michael@0: bool HasBullet() const { michael@0: return mFlags.mHasBullet; michael@0: } michael@0: michael@0: // mHadFloatPushed bit michael@0: void SetHadFloatPushed() { michael@0: mFlags.mHadFloatPushed = true; michael@0: } michael@0: void ClearHadFloatPushed() { michael@0: mFlags.mHadFloatPushed = false; michael@0: } michael@0: bool HadFloatPushed() const { michael@0: return mFlags.mHadFloatPushed; michael@0: } michael@0: michael@0: private: michael@0: // Add a hash table for fast lookup when the line has more frames than this. michael@0: static const uint32_t kMinChildCountForHashtable = 200; michael@0: michael@0: /** michael@0: * Take ownership of aFromLine's hash table and remove the frames that michael@0: * stay on aFromLine from it, i.e. aFromLineNewCount frames starting with michael@0: * mFirstChild. This method is used to optimize moving a large number michael@0: * of frames from one line to the next. michael@0: */ michael@0: void StealHashTableFrom(nsLineBox* aFromLine, uint32_t aFromLineNewCount); michael@0: michael@0: /** michael@0: * Does the equivalent of this->NoteFrameAdded and aFromLine->NoteFrameRemoved michael@0: * for each frame on this line, but in a optimized way. michael@0: */ michael@0: void NoteFramesMovedFrom(nsLineBox* aFromLine); michael@0: michael@0: void SwitchToHashtable() michael@0: { michael@0: MOZ_ASSERT(!mFlags.mHasHashedFrames); michael@0: uint32_t count = GetChildCount(); michael@0: mFlags.mHasHashedFrames = 1; michael@0: uint32_t minSize = michael@0: std::max(kMinChildCountForHashtable, uint32_t(PL_DHASH_MIN_SIZE)); michael@0: mFrames = new nsTHashtable< nsPtrHashKey >(std::max(count, minSize)); michael@0: for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) { michael@0: mFrames->PutEntry(f); michael@0: } michael@0: } michael@0: void SwitchToCounter() { michael@0: MOZ_ASSERT(mFlags.mHasHashedFrames); michael@0: uint32_t count = GetChildCount(); michael@0: delete mFrames; michael@0: mFlags.mHasHashedFrames = 0; michael@0: mChildCount = count; michael@0: } michael@0: michael@0: public: michael@0: int32_t GetChildCount() const { michael@0: return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() : mChildCount; michael@0: } michael@0: michael@0: /** michael@0: * Register that aFrame is now on this line. michael@0: */ michael@0: void NoteFrameAdded(nsIFrame* aFrame) { michael@0: if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { michael@0: mFrames->PutEntry(aFrame); michael@0: } else { michael@0: if (++mChildCount >= kMinChildCountForHashtable) { michael@0: SwitchToHashtable(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Register that aFrame is not on this line anymore. michael@0: */ michael@0: void NoteFrameRemoved(nsIFrame* aFrame) { michael@0: MOZ_ASSERT(GetChildCount() > 0); michael@0: if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) { michael@0: mFrames->RemoveEntry(aFrame); michael@0: if (mFrames->Count() < kMinChildCountForHashtable) { michael@0: SwitchToCounter(); michael@0: } michael@0: } else { michael@0: --mChildCount; michael@0: } michael@0: } michael@0: michael@0: // mBreakType value michael@0: // Break information is applied *before* the line if the line is a block, michael@0: // or *after* the line if the line is an inline. Confusing, I know, but michael@0: // using different names should help. michael@0: bool HasBreakBefore() const { michael@0: return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType; michael@0: } michael@0: void SetBreakTypeBefore(uint8_t aBreakType) { michael@0: NS_ASSERTION(IsBlock(), "Only blocks have break-before"); michael@0: NS_ASSERTION(aBreakType == NS_STYLE_CLEAR_NONE || michael@0: aBreakType == NS_STYLE_CLEAR_LEFT || michael@0: aBreakType == NS_STYLE_CLEAR_RIGHT || michael@0: aBreakType == NS_STYLE_CLEAR_BOTH, michael@0: "Only float break types are allowed before a line"); michael@0: mFlags.mBreakType = aBreakType; michael@0: } michael@0: uint8_t GetBreakTypeBefore() const { michael@0: return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE; michael@0: } michael@0: michael@0: bool HasBreakAfter() const { michael@0: return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType; michael@0: } michael@0: void SetBreakTypeAfter(uint8_t aBreakType) { michael@0: NS_ASSERTION(!IsBlock(), "Only inlines have break-after"); michael@0: NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type"); michael@0: mFlags.mBreakType = aBreakType; michael@0: } michael@0: bool HasFloatBreakAfter() const { michael@0: return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType || michael@0: NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType || michael@0: NS_STYLE_CLEAR_BOTH == mFlags.mBreakType); michael@0: } michael@0: uint8_t GetBreakTypeAfter() const { michael@0: return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE; michael@0: } michael@0: michael@0: // mCarriedOutBottomMargin value michael@0: nsCollapsingMargin GetCarriedOutBottomMargin() const; michael@0: // Returns true if the margin changed michael@0: bool SetCarriedOutBottomMargin(nsCollapsingMargin aValue); michael@0: michael@0: // mFloats michael@0: bool HasFloats() const { michael@0: return (IsInline() && mInlineData) && mInlineData->mFloats.NotEmpty(); michael@0: } michael@0: nsFloatCache* GetFirstFloat(); michael@0: void FreeFloats(nsFloatCacheFreeList& aFreeList); michael@0: void AppendFloats(nsFloatCacheFreeList& aFreeList); michael@0: bool RemoveFloat(nsIFrame* aFrame); michael@0: michael@0: // Combined area is the area of the line that should influence the michael@0: // overflow area of its parent block. The combined area should be michael@0: // used for painting-related things, but should never be used for michael@0: // layout (except for handling of 'overflow'). michael@0: void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas); michael@0: nsRect GetOverflowArea(nsOverflowType aType) { michael@0: return mData ? mData->mOverflowAreas.Overflow(aType) : GetPhysicalBounds(); michael@0: } michael@0: nsOverflowAreas GetOverflowAreas() { michael@0: if (mData) { michael@0: return mData->mOverflowAreas; michael@0: } michael@0: nsRect bounds = GetPhysicalBounds(); michael@0: return nsOverflowAreas(bounds, bounds); michael@0: } michael@0: nsRect GetVisualOverflowArea() michael@0: { return GetOverflowArea(eVisualOverflow); } michael@0: nsRect GetScrollableOverflowArea() michael@0: { return GetOverflowArea(eScrollableOverflow); } michael@0: michael@0: void SlideBy(nscoord aDBCoord, nscoord aContainerWidth) { michael@0: NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1, michael@0: "container width doesn't match"); michael@0: mContainerWidth = aContainerWidth; michael@0: mBounds.BStart(mWritingMode) += aDBCoord; michael@0: if (mData) { michael@0: NS_FOR_FRAME_OVERFLOW_TYPES(otype) { michael@0: mData->mOverflowAreas.Overflow(otype).y += aDBCoord; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void IndentBy(nscoord aDICoord, nscoord aContainerWidth) { michael@0: NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1, michael@0: "container width doesn't match"); michael@0: mContainerWidth = aContainerWidth; michael@0: mBounds.IStart(mWritingMode) += aDICoord; michael@0: } michael@0: michael@0: void ExpandBy(nscoord aDISize, nscoord aContainerWidth) { michael@0: NS_ASSERTION(aContainerWidth == mContainerWidth || mContainerWidth == -1, michael@0: "container width doesn't match"); michael@0: mContainerWidth = aContainerWidth; michael@0: mBounds.ISize(mWritingMode) += aDISize; michael@0: } michael@0: michael@0: /** michael@0: * The ascent (distance from top to baseline) of the linebox is the michael@0: * ascent of the anonymous inline box (for which we don't actually michael@0: * create a frame) that wraps all the consecutive inline children of a michael@0: * block. michael@0: * michael@0: * This is currently unused for block lines. michael@0: */ michael@0: nscoord GetAscent() const { return mAscent; } michael@0: void SetAscent(nscoord aAscent) { mAscent = aAscent; } michael@0: michael@0: nscoord BStart() const { michael@0: return mBounds.BStart(mWritingMode); michael@0: } michael@0: nscoord BSize() const { michael@0: return mBounds.BSize(mWritingMode); michael@0: } michael@0: nscoord BEnd() const { michael@0: return mBounds.BEnd(mWritingMode); michael@0: } michael@0: nscoord IStart() const { michael@0: return mBounds.IStart(mWritingMode); michael@0: } michael@0: nscoord ISize() const { michael@0: return mBounds.ISize(mWritingMode); michael@0: } michael@0: nscoord IEnd() const { michael@0: return mBounds.IEnd(mWritingMode); michael@0: } michael@0: void SetBoundsEmpty() { michael@0: mBounds.IStart(mWritingMode) = 0; michael@0: mBounds.ISize(mWritingMode) = 0; michael@0: mBounds.BStart(mWritingMode) = 0; michael@0: mBounds.BSize(mWritingMode) = 0; michael@0: } michael@0: michael@0: static void DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines, michael@0: nsIFrame* aDestructRoot, nsFrameList* aFrames); michael@0: michael@0: // search from end to beginning of [aBegin, aEnd) michael@0: // Returns true if it found the line and false if not. michael@0: // Moves aEnd as it searches so that aEnd points to the resulting line. michael@0: // aLastFrameBeforeEnd is the last frame before aEnd (so if aEnd is michael@0: // the end of the line list, it's just the last frame in the frame michael@0: // list). michael@0: static bool RFindLineContaining(nsIFrame* aFrame, michael@0: const nsLineList_iterator& aBegin, michael@0: nsLineList_iterator& aEnd, michael@0: nsIFrame* aLastFrameBeforeEnd, michael@0: int32_t* aFrameIndexInLine); michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: char* StateToString(char* aBuf, int32_t aBufSize) const; michael@0: michael@0: void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const; michael@0: void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const; michael@0: nsIFrame* LastChild() const; michael@0: #endif michael@0: michael@0: private: michael@0: int32_t IndexOf(nsIFrame* aFrame) const; michael@0: public: michael@0: michael@0: bool Contains(nsIFrame* aFrame) const { michael@0: return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame) michael@0: : IndexOf(aFrame) >= 0; michael@0: } michael@0: michael@0: // whether the line box is "logically" empty (just like nsIFrame::IsEmpty) michael@0: bool IsEmpty() const; michael@0: michael@0: // Call this only while in Reflow() for the block the line belongs michael@0: // to, only between reflowing the line (or sliding it, if we skip michael@0: // reflowing it) and the end of reflowing the block. michael@0: bool CachedIsEmpty(); michael@0: michael@0: void InvalidateCachedIsEmpty() { michael@0: mFlags.mEmptyCacheValid = false; michael@0: } michael@0: michael@0: // For debugging purposes michael@0: bool IsValidCachedIsEmpty() { michael@0: return mFlags.mEmptyCacheValid; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: static int32_t GetCtorCount(); michael@0: #endif michael@0: michael@0: nsIFrame* mFirstChild; michael@0: michael@0: mozilla::WritingMode mWritingMode; michael@0: nscoord mContainerWidth; michael@0: private: michael@0: mozilla::LogicalRect mBounds; michael@0: public: michael@0: const mozilla::LogicalRect& GetBounds() { return mBounds; } michael@0: nsRect GetPhysicalBounds() const michael@0: { michael@0: if (mBounds.IsEmpty()) { michael@0: return nsRect(0, 0, 0, 0); michael@0: } michael@0: michael@0: NS_ASSERTION(mContainerWidth != -1, "mContainerWidth not initialized"); michael@0: return mBounds.GetPhysicalRect(mWritingMode, mContainerWidth); michael@0: } michael@0: void SetBounds(mozilla::WritingMode aWritingMode, michael@0: nscoord aIStart, nscoord aBStart, michael@0: nscoord aISize, nscoord aBSize, michael@0: nscoord aContainerWidth) michael@0: { michael@0: mWritingMode = aWritingMode; michael@0: mContainerWidth = aContainerWidth; michael@0: mBounds = mozilla::LogicalRect(aWritingMode, aIStart, aBStart, michael@0: aISize, aBSize); michael@0: } michael@0: void SetBounds(mozilla::WritingMode aWritingMode, michael@0: nsRect aRect, nscoord aContainerWidth) michael@0: { michael@0: mWritingMode = aWritingMode; michael@0: mContainerWidth = aContainerWidth; michael@0: mBounds = mozilla::LogicalRect(aWritingMode, aRect, aContainerWidth); michael@0: } michael@0: michael@0: // mFlags.mHasHashedFrames says which one to use michael@0: union { michael@0: nsTHashtable< nsPtrHashKey >* mFrames; michael@0: uint32_t mChildCount; michael@0: }; michael@0: michael@0: struct FlagBits { michael@0: uint32_t mDirty : 1; michael@0: uint32_t mPreviousMarginDirty : 1; michael@0: uint32_t mHasClearance : 1; michael@0: uint32_t mBlock : 1; michael@0: uint32_t mImpactedByFloat : 1; michael@0: uint32_t mLineWrapped: 1; michael@0: uint32_t mInvalidateTextRuns : 1; michael@0: 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 michael@0: uint32_t mEmptyCacheValid: 1; michael@0: uint32_t mEmptyCacheState: 1; michael@0: // mHasBullet indicates that this is an inline line whose block's michael@0: // bullet is adjacent to this line and non-empty. michael@0: uint32_t mHasBullet : 1; michael@0: // Indicates that this line *may* have a placeholder for a float michael@0: // that was pushed to a later column or page. michael@0: uint32_t mHadFloatPushed : 1; michael@0: uint32_t mHasHashedFrames: 1; michael@0: uint32_t mBreakType : 4; michael@0: }; michael@0: michael@0: struct ExtraData { michael@0: ExtraData(const nsRect& aBounds) : mOverflowAreas(aBounds, aBounds) { michael@0: } michael@0: nsOverflowAreas mOverflowAreas; michael@0: }; michael@0: michael@0: struct ExtraBlockData : public ExtraData { michael@0: ExtraBlockData(const nsRect& aBounds) michael@0: : ExtraData(aBounds), michael@0: mCarriedOutBottomMargin() michael@0: { michael@0: } michael@0: nsCollapsingMargin mCarriedOutBottomMargin; michael@0: }; michael@0: michael@0: struct ExtraInlineData : public ExtraData { michael@0: ExtraInlineData(const nsRect& aBounds) : ExtraData(aBounds) { michael@0: } michael@0: nsFloatCacheList mFloats; michael@0: }; michael@0: michael@0: protected: michael@0: nscoord mAscent; // see |SetAscent| / |GetAscent| michael@0: union { michael@0: uint32_t mAllFlags; michael@0: FlagBits mFlags; michael@0: }; michael@0: michael@0: union { michael@0: ExtraData* mData; michael@0: ExtraBlockData* mBlockData; michael@0: ExtraInlineData* mInlineData; michael@0: }; michael@0: michael@0: void Cleanup(); michael@0: void MaybeFreeData(); michael@0: }; michael@0: michael@0: /** michael@0: * A linked list type where the items in the list must inherit from michael@0: * a link type to fuse allocations. michael@0: * michael@0: * API heavily based on the |list| class in the C++ standard. michael@0: */ michael@0: michael@0: class nsLineList_iterator { michael@0: public: michael@0: friend class nsLineList; michael@0: friend class nsLineList_reverse_iterator; michael@0: friend class nsLineList_const_iterator; michael@0: friend class nsLineList_const_reverse_iterator; michael@0: michael@0: typedef nsLineList_iterator iterator_self_type; michael@0: typedef nsLineList_reverse_iterator iterator_reverse_type; michael@0: michael@0: typedef nsLineBox& reference; michael@0: typedef const nsLineBox& const_reference; michael@0: michael@0: typedef nsLineBox* pointer; michael@0: typedef const nsLineBox* const_pointer; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef int32_t difference_type; michael@0: michael@0: typedef nsLineLink link_type; michael@0: michael@0: #ifdef DEBUG michael@0: nsLineList_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); } michael@0: #else michael@0: // Auto generated default constructor OK. michael@0: #endif michael@0: // Auto generated copy-constructor OK. michael@0: michael@0: inline iterator_self_type& michael@0: operator=(const iterator_self_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_reverse_type& aOther); michael@0: michael@0: iterator_self_type& operator++() michael@0: { michael@0: mCurrent = mCurrent->_mNext; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator++(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mNext; michael@0: return rv; michael@0: } michael@0: michael@0: iterator_self_type& operator--() michael@0: { michael@0: mCurrent = mCurrent->_mPrev; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator--(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mPrev; michael@0: return rv; michael@0: } michael@0: michael@0: reference operator*() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: pointer operator->() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: pointer get() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: operator pointer() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: const_reference operator*() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer operator->() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: #ifndef __MWERKS__ michael@0: operator const_pointer() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: #endif /* !__MWERKS__ */ michael@0: michael@0: iterator_self_type next() michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return ++copy; michael@0: } michael@0: michael@0: const iterator_self_type next() const michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return ++copy; michael@0: } michael@0: michael@0: iterator_self_type prev() michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return --copy; michael@0: } michael@0: michael@0: const iterator_self_type prev() const michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return --copy; michael@0: } michael@0: michael@0: // Passing by value rather than by reference and reference to const michael@0: // to keep AIX happy. michael@0: bool operator==(const iterator_self_type aOther) const michael@0: { michael@0: NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) const michael@0: { michael@0: NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: bool operator==(const iterator_self_type aOther) michael@0: { michael@0: NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) michael@0: { michael@0: NS_ABORT_IF_FALSE(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: michael@0: private: michael@0: link_type *mCurrent; michael@0: #ifdef DEBUG michael@0: link_type *mListLink; // the list's link, i.e., the end michael@0: #endif michael@0: }; michael@0: michael@0: class nsLineList_reverse_iterator { michael@0: michael@0: public: michael@0: michael@0: friend class nsLineList; michael@0: friend class nsLineList_iterator; michael@0: friend class nsLineList_const_iterator; michael@0: friend class nsLineList_const_reverse_iterator; michael@0: michael@0: typedef nsLineList_reverse_iterator iterator_self_type; michael@0: typedef nsLineList_iterator iterator_reverse_type; michael@0: michael@0: typedef nsLineBox& reference; michael@0: typedef const nsLineBox& const_reference; michael@0: michael@0: typedef nsLineBox* pointer; michael@0: typedef const nsLineBox* const_pointer; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef int32_t difference_type; michael@0: michael@0: typedef nsLineLink link_type; michael@0: michael@0: #ifdef DEBUG michael@0: nsLineList_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); } michael@0: #else michael@0: // Auto generated default constructor OK. michael@0: #endif michael@0: // Auto generated copy-constructor OK. michael@0: michael@0: inline iterator_self_type& michael@0: operator=(const iterator_reverse_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_self_type& aOther); michael@0: michael@0: iterator_self_type& operator++() michael@0: { michael@0: mCurrent = mCurrent->_mPrev; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator++(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mPrev; michael@0: return rv; michael@0: } michael@0: michael@0: iterator_self_type& operator--() michael@0: { michael@0: mCurrent = mCurrent->_mNext; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator--(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mNext; michael@0: return rv; michael@0: } michael@0: michael@0: reference operator*() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: pointer operator->() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: pointer get() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: operator pointer() michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: const_reference operator*() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer operator->() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: #ifndef __MWERKS__ michael@0: operator const_pointer() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: #endif /* !__MWERKS__ */ michael@0: michael@0: // Passing by value rather than by reference and reference to const michael@0: // to keep AIX happy. michael@0: bool operator==(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: bool operator==(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: michael@0: private: michael@0: link_type *mCurrent; michael@0: #ifdef DEBUG michael@0: link_type *mListLink; // the list's link, i.e., the end michael@0: #endif michael@0: }; michael@0: michael@0: class nsLineList_const_iterator { michael@0: public: michael@0: michael@0: friend class nsLineList; michael@0: friend class nsLineList_iterator; michael@0: friend class nsLineList_reverse_iterator; michael@0: friend class nsLineList_const_reverse_iterator; michael@0: michael@0: typedef nsLineList_const_iterator iterator_self_type; michael@0: typedef nsLineList_const_reverse_iterator iterator_reverse_type; michael@0: typedef nsLineList_iterator iterator_nonconst_type; michael@0: typedef nsLineList_reverse_iterator iterator_nonconst_reverse_type; michael@0: michael@0: typedef nsLineBox& reference; michael@0: typedef const nsLineBox& const_reference; michael@0: michael@0: typedef nsLineBox* pointer; michael@0: typedef const nsLineBox* const_pointer; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef int32_t difference_type; michael@0: michael@0: typedef nsLineLink link_type; michael@0: michael@0: #ifdef DEBUG michael@0: nsLineList_const_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); } michael@0: #else michael@0: // Auto generated default constructor OK. michael@0: #endif michael@0: // Auto generated copy-constructor OK. michael@0: michael@0: inline iterator_self_type& michael@0: operator=(const iterator_nonconst_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_nonconst_reverse_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_self_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_reverse_type& aOther); michael@0: michael@0: iterator_self_type& operator++() michael@0: { michael@0: mCurrent = mCurrent->_mNext; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator++(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mNext; michael@0: return rv; michael@0: } michael@0: michael@0: iterator_self_type& operator--() michael@0: { michael@0: mCurrent = mCurrent->_mPrev; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator--(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mPrev; michael@0: return rv; michael@0: } michael@0: michael@0: const_reference operator*() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer operator->() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer get() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: #ifndef __MWERKS__ michael@0: operator const_pointer() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: #endif /* !__MWERKS__ */ michael@0: michael@0: const iterator_self_type next() const michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return ++copy; michael@0: } michael@0: michael@0: const iterator_self_type prev() const michael@0: { michael@0: iterator_self_type copy(*this); michael@0: return --copy; michael@0: } michael@0: michael@0: // Passing by value rather than by reference and reference to const michael@0: // to keep AIX happy. michael@0: bool operator==(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: bool operator==(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: michael@0: private: michael@0: const link_type *mCurrent; michael@0: #ifdef DEBUG michael@0: const link_type *mListLink; // the list's link, i.e., the end michael@0: #endif michael@0: }; michael@0: michael@0: class nsLineList_const_reverse_iterator { michael@0: public: michael@0: michael@0: friend class nsLineList; michael@0: friend class nsLineList_iterator; michael@0: friend class nsLineList_reverse_iterator; michael@0: friend class nsLineList_const_iterator; michael@0: michael@0: typedef nsLineList_const_reverse_iterator iterator_self_type; michael@0: typedef nsLineList_const_iterator iterator_reverse_type; michael@0: typedef nsLineList_iterator iterator_nonconst_reverse_type; michael@0: typedef nsLineList_reverse_iterator iterator_nonconst_type; michael@0: michael@0: typedef nsLineBox& reference; michael@0: typedef const nsLineBox& const_reference; michael@0: michael@0: typedef nsLineBox* pointer; michael@0: typedef const nsLineBox* const_pointer; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef int32_t difference_type; michael@0: michael@0: typedef nsLineLink link_type; michael@0: michael@0: #ifdef DEBUG michael@0: nsLineList_const_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); } michael@0: #else michael@0: // Auto generated default constructor OK. michael@0: #endif michael@0: // Auto generated copy-constructor OK. michael@0: michael@0: inline iterator_self_type& michael@0: operator=(const iterator_nonconst_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_nonconst_reverse_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_self_type& aOther); michael@0: inline iterator_self_type& michael@0: operator=(const iterator_reverse_type& aOther); michael@0: michael@0: iterator_self_type& operator++() michael@0: { michael@0: mCurrent = mCurrent->_mPrev; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator++(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mPrev; michael@0: return rv; michael@0: } michael@0: michael@0: iterator_self_type& operator--() michael@0: { michael@0: mCurrent = mCurrent->_mNext; michael@0: return *this; michael@0: } michael@0: michael@0: iterator_self_type operator--(int) michael@0: { michael@0: iterator_self_type rv(*this); michael@0: mCurrent = mCurrent->_mNext; michael@0: return rv; michael@0: } michael@0: michael@0: const_reference operator*() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return *static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer operator->() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: const_pointer get() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: michael@0: #ifndef __MWERKS__ michael@0: operator const_pointer() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mCurrent != mListLink, "running past end"); michael@0: return static_cast(mCurrent); michael@0: } michael@0: #endif /* !__MWERKS__ */ michael@0: michael@0: // Passing by value rather than by reference and reference to const michael@0: // to keep AIX happy. michael@0: bool operator==(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) const michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: bool operator==(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent == aOther.mCurrent; michael@0: } michael@0: bool operator!=(const iterator_self_type aOther) michael@0: { michael@0: NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists"); michael@0: return mCurrent != aOther.mCurrent; michael@0: } michael@0: michael@0: //private: michael@0: const link_type *mCurrent; michael@0: #ifdef DEBUG michael@0: const link_type *mListLink; // the list's link, i.e., the end michael@0: #endif michael@0: }; michael@0: michael@0: class nsLineList { michael@0: michael@0: public: michael@0: michael@0: friend class nsLineList_iterator; michael@0: friend class nsLineList_reverse_iterator; michael@0: friend class nsLineList_const_iterator; michael@0: friend class nsLineList_const_reverse_iterator; michael@0: michael@0: typedef uint32_t size_type; michael@0: typedef int32_t difference_type; michael@0: michael@0: typedef nsLineLink link_type; michael@0: michael@0: private: michael@0: link_type mLink; michael@0: michael@0: public: michael@0: typedef nsLineList self_type; michael@0: michael@0: typedef nsLineBox& reference; michael@0: typedef const nsLineBox& const_reference; michael@0: michael@0: typedef nsLineBox* pointer; michael@0: typedef const nsLineBox* const_pointer; michael@0: michael@0: typedef nsLineList_iterator iterator; michael@0: typedef nsLineList_reverse_iterator reverse_iterator; michael@0: typedef nsLineList_const_iterator const_iterator; michael@0: typedef nsLineList_const_reverse_iterator const_reverse_iterator; michael@0: michael@0: nsLineList() michael@0: { michael@0: MOZ_COUNT_CTOR(nsLineList); michael@0: clear(); michael@0: } michael@0: michael@0: ~nsLineList() michael@0: { michael@0: MOZ_COUNT_DTOR(nsLineList); michael@0: } michael@0: michael@0: const_iterator begin() const michael@0: { michael@0: const_iterator rv; michael@0: rv.mCurrent = mLink._mNext; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: iterator begin() michael@0: { michael@0: iterator rv; michael@0: rv.mCurrent = mLink._mNext; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: iterator begin(nsLineBox* aLine) michael@0: { michael@0: iterator rv; michael@0: rv.mCurrent = aLine; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: const_iterator end() const michael@0: { michael@0: const_iterator rv; michael@0: rv.mCurrent = &mLink; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: iterator end() michael@0: { michael@0: iterator rv; michael@0: rv.mCurrent = &mLink; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: const_reverse_iterator rbegin() const michael@0: { michael@0: const_reverse_iterator rv; michael@0: rv.mCurrent = mLink._mPrev; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: reverse_iterator rbegin() michael@0: { michael@0: reverse_iterator rv; michael@0: rv.mCurrent = mLink._mPrev; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: reverse_iterator rbegin(nsLineBox* aLine) michael@0: { michael@0: reverse_iterator rv; michael@0: rv.mCurrent = aLine; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: const_reverse_iterator rend() const michael@0: { michael@0: const_reverse_iterator rv; michael@0: rv.mCurrent = &mLink; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: reverse_iterator rend() michael@0: { michael@0: reverse_iterator rv; michael@0: rv.mCurrent = &mLink; michael@0: #ifdef DEBUG michael@0: rv.mListLink = &mLink; michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: bool empty() const michael@0: { michael@0: return mLink._mNext == &mLink; michael@0: } michael@0: michael@0: // NOTE: O(N). michael@0: size_type size() const michael@0: { michael@0: size_type count = 0; michael@0: for (const link_type *cur = mLink._mNext; michael@0: cur != &mLink; michael@0: cur = cur->_mNext) michael@0: { michael@0: ++count; michael@0: } michael@0: return count; michael@0: } michael@0: michael@0: pointer front() michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to return"); michael@0: return static_cast(mLink._mNext); michael@0: } michael@0: michael@0: const_pointer front() const michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to return"); michael@0: return static_cast(mLink._mNext); michael@0: } michael@0: michael@0: pointer back() michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to return"); michael@0: return static_cast(mLink._mPrev); michael@0: } michael@0: michael@0: const_pointer back() const michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to return"); michael@0: return static_cast(mLink._mPrev); michael@0: } michael@0: michael@0: void push_front(pointer aNew) michael@0: { michael@0: aNew->_mNext = mLink._mNext; michael@0: mLink._mNext->_mPrev = aNew; michael@0: aNew->_mPrev = &mLink; michael@0: mLink._mNext = aNew; michael@0: } michael@0: michael@0: void pop_front() michael@0: // NOTE: leaves dangling next/prev pointers michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to pop"); michael@0: link_type *newFirst = mLink._mNext->_mNext; michael@0: newFirst->_mPrev = &mLink; michael@0: // mLink._mNext->_mNext = nullptr; michael@0: // mLink._mNext->_mPrev = nullptr; michael@0: mLink._mNext = newFirst; michael@0: } michael@0: michael@0: void push_back(pointer aNew) michael@0: { michael@0: aNew->_mPrev = mLink._mPrev; michael@0: mLink._mPrev->_mNext = aNew; michael@0: aNew->_mNext = &mLink; michael@0: mLink._mPrev = aNew; michael@0: } michael@0: michael@0: void pop_back() michael@0: // NOTE: leaves dangling next/prev pointers michael@0: { michael@0: NS_ASSERTION(!empty(), "no element to pop"); michael@0: link_type *newLast = mLink._mPrev->_mPrev; michael@0: newLast->_mNext = &mLink; michael@0: // mLink._mPrev->_mPrev = nullptr; michael@0: // mLink._mPrev->_mNext = nullptr; michael@0: mLink._mPrev = newLast; michael@0: } michael@0: michael@0: // inserts x before position michael@0: iterator before_insert(iterator position, pointer x) michael@0: { michael@0: // use |mCurrent| to prevent DEBUG_PASS_END assertions michael@0: x->_mPrev = position.mCurrent->_mPrev; michael@0: x->_mNext = position.mCurrent; michael@0: position.mCurrent->_mPrev->_mNext = x; michael@0: position.mCurrent->_mPrev = x; michael@0: return --position; michael@0: } michael@0: michael@0: // inserts x after position michael@0: iterator after_insert(iterator position, pointer x) michael@0: { michael@0: // use |mCurrent| to prevent DEBUG_PASS_END assertions michael@0: x->_mNext = position.mCurrent->_mNext; michael@0: x->_mPrev = position.mCurrent; michael@0: position.mCurrent->_mNext->_mPrev = x; michael@0: position.mCurrent->_mNext = x; michael@0: return ++position; michael@0: } michael@0: michael@0: // returns iterator pointing to after the element michael@0: iterator erase(iterator position) michael@0: // NOTE: leaves dangling next/prev pointers michael@0: { michael@0: position->_mPrev->_mNext = position->_mNext; michael@0: position->_mNext->_mPrev = position->_mPrev; michael@0: return ++position; michael@0: } michael@0: michael@0: void swap(self_type& y) michael@0: { michael@0: link_type tmp(y.mLink); michael@0: y.mLink = mLink; michael@0: mLink = tmp; michael@0: michael@0: if (!empty()) { michael@0: mLink._mNext->_mPrev = &mLink; michael@0: mLink._mPrev->_mNext = &mLink; michael@0: } michael@0: michael@0: if (!y.empty()) { michael@0: y.mLink._mNext->_mPrev = &y.mLink; michael@0: y.mLink._mPrev->_mNext = &y.mLink; michael@0: } michael@0: } michael@0: michael@0: void clear() michael@0: // NOTE: leaves dangling next/prev pointers michael@0: { michael@0: mLink._mNext = &mLink; michael@0: mLink._mPrev = &mLink; michael@0: } michael@0: michael@0: // inserts the conts of x before position and makes x empty michael@0: void splice(iterator position, self_type& x) michael@0: { michael@0: // use |mCurrent| to prevent DEBUG_PASS_END assertions michael@0: position.mCurrent->_mPrev->_mNext = x.mLink._mNext; michael@0: x.mLink._mNext->_mPrev = position.mCurrent->_mPrev; michael@0: x.mLink._mPrev->_mNext = position.mCurrent; michael@0: position.mCurrent->_mPrev = x.mLink._mPrev; michael@0: x.clear(); michael@0: } michael@0: michael@0: // Inserts element *i from list x before position and removes michael@0: // it from x. michael@0: void splice(iterator position, self_type& x, iterator i) michael@0: { michael@0: NS_ASSERTION(!x.empty(), "Can't insert from empty list."); michael@0: NS_ASSERTION(position != i && position.mCurrent != i->_mNext, michael@0: "We don't check for this case."); michael@0: michael@0: // remove from |x| michael@0: i->_mPrev->_mNext = i->_mNext; michael@0: i->_mNext->_mPrev = i->_mPrev; michael@0: michael@0: // use |mCurrent| to prevent DEBUG_PASS_END assertions michael@0: // link into |this|, before-side michael@0: i->_mPrev = position.mCurrent->_mPrev; michael@0: position.mCurrent->_mPrev->_mNext = i.get(); michael@0: michael@0: // link into |this|, after-side michael@0: i->_mNext = position.mCurrent; michael@0: position.mCurrent->_mPrev = i.get(); michael@0: } michael@0: michael@0: // Inserts elements in [|first|, |last|), which are in |x|, michael@0: // into |this| before |position| and removes them from |x|. michael@0: void splice(iterator position, self_type& x, iterator first, michael@0: iterator last) michael@0: { michael@0: NS_ASSERTION(!x.empty(), "Can't insert from empty list."); michael@0: michael@0: if (first == last) michael@0: return; michael@0: michael@0: --last; // so we now want to move [first, last] michael@0: // remove from |x| michael@0: first->_mPrev->_mNext = last->_mNext; michael@0: last->_mNext->_mPrev = first->_mPrev; michael@0: michael@0: // use |mCurrent| to prevent DEBUG_PASS_END assertions michael@0: // link into |this|, before-side michael@0: first->_mPrev = position.mCurrent->_mPrev; michael@0: position.mCurrent->_mPrev->_mNext = first.get(); michael@0: michael@0: // link into |this|, after-side michael@0: last->_mNext = position.mCurrent; michael@0: position.mCurrent->_mPrev = last.get(); michael@0: } michael@0: michael@0: }; michael@0: michael@0: michael@0: // Many of these implementations of operator= don't work yet. I don't michael@0: // know why. michael@0: michael@0: #ifdef DEBUG michael@0: michael@0: // NOTE: ASSIGN_FROM is meant to be used *only* as the entire body michael@0: // of a function and therefore lacks PR_{BEGIN,END}_MACRO michael@0: #define ASSIGN_FROM(other_) \ michael@0: mCurrent = other_.mCurrent; \ michael@0: mListLink = other_.mListLink; \ michael@0: return *this; michael@0: michael@0: #else /* !NS_LINELIST_DEBUG_PASS_END */ michael@0: michael@0: #define ASSIGN_FROM(other_) \ michael@0: mCurrent = other_.mCurrent; \ michael@0: return *this; michael@0: michael@0: #endif /* !NS_LINELIST_DEBUG_PASS_END */ michael@0: michael@0: inline michael@0: nsLineList_iterator& michael@0: nsLineList_iterator::operator=(const nsLineList_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_iterator& michael@0: nsLineList_iterator::operator=(const nsLineList_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_reverse_iterator& michael@0: nsLineList_reverse_iterator::operator=(const nsLineList_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_reverse_iterator& michael@0: nsLineList_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_iterator& michael@0: nsLineList_const_iterator::operator=(const nsLineList_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_iterator& michael@0: nsLineList_const_iterator::operator=(const nsLineList_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_iterator& michael@0: nsLineList_const_iterator::operator=(const nsLineList_const_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_iterator& michael@0: nsLineList_const_iterator::operator=(const nsLineList_const_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_reverse_iterator& michael@0: nsLineList_const_reverse_iterator::operator=(const nsLineList_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_reverse_iterator& michael@0: nsLineList_const_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_reverse_iterator& michael@0: nsLineList_const_reverse_iterator::operator=(const nsLineList_const_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: inline michael@0: nsLineList_const_reverse_iterator& michael@0: nsLineList_const_reverse_iterator::operator=(const nsLineList_const_reverse_iterator& aOther) michael@0: { michael@0: ASSIGN_FROM(aOther) michael@0: } michael@0: michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: class nsLineIterator MOZ_FINAL : public nsILineIterator michael@0: { michael@0: public: michael@0: nsLineIterator(); michael@0: ~nsLineIterator(); michael@0: michael@0: virtual void DisposeLineIterator() MOZ_OVERRIDE; michael@0: michael@0: virtual int32_t GetNumLines() MOZ_OVERRIDE; michael@0: virtual bool GetDirection() MOZ_OVERRIDE; michael@0: NS_IMETHOD GetLine(int32_t aLineNumber, michael@0: nsIFrame** aFirstFrameOnLine, michael@0: int32_t* aNumFramesOnLine, michael@0: nsRect& aLineBounds, michael@0: uint32_t* aLineFlags) MOZ_OVERRIDE; michael@0: virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) MOZ_OVERRIDE; michael@0: NS_IMETHOD FindFrameAt(int32_t aLineNumber, michael@0: nscoord aX, michael@0: nsIFrame** aFrameFound, michael@0: bool* aXIsBeforeFirstFrame, michael@0: bool* aXIsAfterLastFrame) MOZ_OVERRIDE; michael@0: michael@0: NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) MOZ_OVERRIDE; michael@0: NS_IMETHOD CheckLineOrder(int32_t aLine, michael@0: bool *aIsReordered, michael@0: nsIFrame **aFirstVisual, michael@0: nsIFrame **aLastVisual) MOZ_OVERRIDE; michael@0: nsresult Init(nsLineList& aLines, bool aRightToLeft); michael@0: michael@0: private: michael@0: nsLineBox* PrevLine() { michael@0: if (0 == mIndex) { michael@0: return nullptr; michael@0: } michael@0: return mLines[--mIndex]; michael@0: } michael@0: michael@0: nsLineBox* NextLine() { michael@0: if (mIndex >= mNumLines - 1) { michael@0: return nullptr; michael@0: } michael@0: return mLines[++mIndex]; michael@0: } michael@0: michael@0: nsLineBox* LineAt(int32_t aIndex) { michael@0: if ((aIndex < 0) || (aIndex >= mNumLines)) { michael@0: return nullptr; michael@0: } michael@0: return mLines[aIndex]; michael@0: } michael@0: michael@0: nsLineBox** mLines; michael@0: int32_t mIndex; michael@0: int32_t mNumLines; michael@0: bool mRightToLeft; michael@0: }; michael@0: michael@0: #endif /* nsLineBox_h___ */