troy%netscape.com d4f29d1b5f Now line boxes are allocated out of the pres shell arena. This reduces the
overhead of memory allocation, and it gets us recycling which speeds up
resize reflows


git-svn-id: svn://10.0.0.236/trunk@62680 18797224-902f-48f8-a5cc-f745e15eee43
2000-03-12 03:00:51 +00:00

433 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsLineBox_h___
#define nsLineBox_h___
#include "nsVoidArray.h"
#include "nsPlaceholderFrame.h"
#include "nsILineIterator.h"
#include "nsISizeOfHandler.h"
class nsISpaceManager;
class nsLineBox;
class nsFloaterCache;
class nsFloaterCacheList;
class nsFloaterCacheFreeList;
// State cached after reflowing a floater. This state is used during
// incremental reflow when we avoid reflowing a floater.
class nsFloaterCache {
public:
nsFloaterCache();
#ifdef DEBUG
~nsFloaterCache();
#else
~nsFloaterCache() { }
#endif
nsFloaterCache* Next() const { return mNext; }
nsPlaceholderFrame* mPlaceholder; // nsPlaceholderFrame
// This will be true if the floater was placed on the current line
// instead of below the current line.
PRBool mIsCurrentLineFloater;
nsMargin mMargins; // computed margins
nsMargin mOffsets; // computed offsets (relative pos)
// Region in the spacemanager impacted by this floater; the
// coordinates are relative to the containing block frame. The
// region includes the margins around the floater, but doesn't
// include the relative offsets.
nsRect mRegion;
// Combined area for the floater. This will not include the margins
// for the floater. Like mRegion, the coordinates are relative to
// the containing block frame.
nsRect mCombinedArea;
protected:
nsFloaterCache* mNext;
friend class nsFloaterCacheList;
friend class nsFloaterCacheFreeList;
};
//----------------------------------------
class nsFloaterCacheList {
public:
nsFloaterCacheList() : mHead(nsnull) { }
~nsFloaterCacheList();
PRBool IsEmpty() const {
return nsnull == mHead;
}
PRBool NotEmpty() const {
return nsnull != mHead;
}
nsFloaterCache* Head() const {
return mHead;
}
nsFloaterCache* Tail() const;
nsFloaterCache* Find(nsIFrame* aOutOfFlowFrame);
void Remove(nsFloaterCache* aElement);
void Append(nsFloaterCacheFreeList& aList);
#ifdef DEBUG
void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
#endif
protected:
nsFloaterCache* mHead;
friend class nsFloaterCacheFreeList;
};
//---------------------------------------
class nsFloaterCacheFreeList : public nsFloaterCacheList {
public:
nsFloaterCacheFreeList() : mTail(nsnull) { }
~nsFloaterCacheFreeList() { }
// Steal away aList's nsFloaterCache objects and put them on this
// free-list.
void Append(nsFloaterCacheList& aList);
void Append(nsFloaterCache* aFloaterCache);
// Allocate a new nsFloaterCache object
nsFloaterCache* Alloc();
protected:
nsFloaterCache* mTail;
friend class nsFloaterCacheList;
};
//----------------------------------------------------------------------
#define LINE_MAX_BREAK_TYPE ((1 << 4) - 1)
#define LINE_MAX_CHILD_COUNT ((1 << 24) - 1)
#if NS_STYLE_CLEAR_LAST_VALUE > 15
need to rearrange the mBits bitfield;
#endif
// Funtion to create a line box
nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
PRInt32 aCount, PRBool aIsBlock);
/**
* The nsLineBox class represents a horizontal line of frames. It contains
* enough state to support incremental reflow of the frames, event handling
* for the frames, and rendering of the frames.
*/
class nsLineBox {
private:
nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock);
~nsLineBox();
// Overloaded new operator. Uses an arena (which comes from the presShell)
// to perform the allocation.
void* operator new(size_t sz, nsIPresShell* aPresShell);
void operator delete(void* aPtr, size_t sz);
public:
// Use these two functions to allocate and destroy line boxes
friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
PRInt32 aCount, PRBool aIsBlock);
void Destroy(nsIPresShell* aPresShell);
// mBlock bit
PRBool IsBlock() const {
return mFlags.mBlock;
}
PRBool IsInline() const {
return 0 == mFlags.mBlock;
}
// mDirty bit
void MarkDirty() {
mFlags.mDirty = 1;
}
void ClearDirty() {
mFlags.mDirty = 0;
}
PRBool IsDirty() const {
return mFlags.mDirty;
}
// mImpactedByFloater bit
void SetLineIsImpactedByFloater(PRBool aValue) {
mFlags.mImpactedByFloater = aValue;
}
PRBool IsImpactedByFloater() const {
return mFlags.mImpactedByFloater;
}
// mTrimmed bit
void SetTrimmed(PRBool aOn) {
mFlags.mTrimmed = aOn;
}
PRBool IsTrimmed() const {
return mFlags.mTrimmed;
}
// mHasPercentageChild bit
void SetHasPercentageChild(PRBool aOn) {
mFlags.mHasPercentageChild = aOn;
}
PRBool HasPercentageChild() const {
return mFlags.mHasPercentageChild;
}
// mLineWrapped bit
void SetLineWrapped(PRBool aOn) {
mFlags.mLineWrapped = aOn;
}
PRBool IsLineWrapped() const {
return mFlags.mLineWrapped;
}
// mChildCount value
PRInt32 GetChildCount() const {
return (PRInt32) mFlags.mChildCount;
}
void SetChildCount(PRInt32 aNewCount) {
if (NS_WARN_IF_FALSE(aNewCount >= 0, "negative child count")) {
aNewCount = 0;
}
if (aNewCount > LINE_MAX_CHILD_COUNT) {
aNewCount = LINE_MAX_CHILD_COUNT;
}
mFlags.mChildCount = aNewCount;
}
// mBreakType value
PRBool HasBreak() const {
return NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
}
void SetBreakType(PRUint8 aBreakType) {
NS_WARN_IF_FALSE(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
mFlags.mBreakType = aBreakType;
}
PRUint8 GetBreakType() const {
return mFlags.mBreakType;
}
// mCarriedOutBottomMargin value
nscoord GetCarriedOutBottomMargin() const;
void SetCarriedOutBottomMargin(nscoord aValue);
// mFloaters
PRBool HasFloaters() const {
return (IsInline() && mInlineData) && mInlineData->mFloaters.NotEmpty();
}
nsFloaterCache* GetFirstFloater();
void FreeFloaters(nsFloaterCacheFreeList& aFreeList);
void AppendFloaters(nsFloaterCacheFreeList& aFreeList);
PRBool RemoveFloater(nsIFrame* aFrame);
void RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager);
// Combined area
void SetCombinedArea(const nsRect& aCombinedArea);
void GetCombinedArea(nsRect* aResult);
PRBool CombinedAreaIntersects(const nsRect& aDamageRect) {
nsRect* ca = (mData ? &mData->mCombinedArea : &mBounds);
return !((ca->YMost() <= aDamageRect.y) ||
(ca->y >= aDamageRect.YMost()));
}
void SlideBy(nscoord aDY) {
mBounds.y += aDY;
if (mData) {
mData->mCombinedArea.y += aDY;
}
}
//----------------------------------------
nscoord GetHeight() const {
return mBounds.height;
}
static void DeleteLineList(nsIPresContext* aPresContext, nsLineBox* aLine);
static nsLineBox* LastLine(nsLineBox* aLine);
static nsLineBox* FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame,
PRInt32* aFrameIndexInLine);
#ifdef DEBUG
void List(nsIPresContext* aPresContext, FILE* out, PRInt32 aIndent) const;
#endif
nsIFrame* LastChild() const;
PRBool IsLastChild(nsIFrame* aFrame) const;
char* StateToString(char* aBuf, PRInt32 aBufSize) const;
PRInt32 IndexOf(nsIFrame* aFrame) const;
PRBool Contains(nsIFrame* aFrame) const {
return IndexOf(aFrame) >= 0;
}
#ifdef DEBUG
nsIAtom* SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
static PRInt32 GetCtorCount();
static PRInt32 ListLength(nsLineBox* aLine);
#endif
nsIFrame* mFirstChild;
nsLineBox* mNext;
nsRect mBounds;
nscoord mMaxElementWidth; // width part of max-element-size
nscoord mMaximumWidth; // maximum width (needed for incremental reflow of tables)
struct FlagBits {
PRUint32 mDirty : 1;
PRUint32 mBlock : 1;
PRUint32 mImpactedByFloater : 1;
PRUint32 mTrimmed : 1;
PRUint32 mHasPercentageChild : 1;
PRUint32 mLineWrapped: 1;
PRUint32 mBreakType : 4;
PRUint32 mChildCount : 22;
};
struct ExtraData {
ExtraData(const nsRect& aBounds) : mCombinedArea(aBounds) {
}
nsRect mCombinedArea;
};
struct ExtraBlockData : public ExtraData {
ExtraBlockData(const nsRect& aBounds) : ExtraData(aBounds) {
mCarriedOutBottomMargin = 0;
}
nscoord mCarriedOutBottomMargin;
};
struct ExtraInlineData : public ExtraData {
ExtraInlineData(const nsRect& aBounds) : ExtraData(aBounds) {
}
nsFloaterCacheList mFloaters;
};
protected:
union {
PRUint32 mAllFlags;
FlagBits mFlags;
};
union {
ExtraData* mData;
ExtraBlockData* mBlockData;
ExtraInlineData* mInlineData;
};
void Cleanup();
void MaybeFreeData();
};
//----------------------------------------------------------------------
class nsLineIterator : public nsILineIterator {
public:
nsLineIterator();
virtual ~nsLineIterator();
NS_DECL_ISUPPORTS
NS_IMETHOD GetNumLines(PRInt32* aResult);
NS_IMETHOD GetDirection(PRBool* aIsRightToLeft);
NS_IMETHOD GetLine(PRInt32 aLineNumber,
nsIFrame** aFirstFrameOnLine,
PRInt32* aNumFramesOnLine,
nsRect& aLineBounds,
PRUint32* aLineFlags);
NS_IMETHOD FindLineContaining(nsIFrame* aFrame,
PRInt32* aLineNumberResult);
NS_IMETHOD FindLineAt(nscoord aY,
PRInt32* aLineNumberResult);
NS_IMETHOD FindFrameAt(PRInt32 aLineNumber,
nscoord aX,
nsIFrame** aFrameFound,
PRBool* aXIsBeforeFirstFrame,
PRBool* aXIsAfterLastFrame);
nsresult Init(nsLineBox* aLines, PRBool aRightToLeft);
protected:
PRInt32 NumLines() const {
return mNumLines;
}
nsLineBox* CurrentLine() {
return mLines[mIndex];
}
nsLineBox* PrevLine() {
if (0 == mIndex) {
return nsnull;
}
return mLines[--mIndex];
}
nsLineBox* NextLine() {
if (mIndex >= mNumLines - 1) {
return nsnull;
}
return mLines[++mIndex];
}
nsLineBox* LineAt(PRInt32 aIndex) {
if ((aIndex < 0) || (aIndex >= mNumLines)) {
return nsnull;
}
return mLines[aIndex];
}
nsLineBox** mLines;
PRInt32 mIndex;
PRInt32 mNumLines;
PRBool mRightToLeft;
};
#endif /* nsLineBox_h___ */