Keep a "last band we touched" cursor so we can avoid seeking through the whole

linked list for multiple appends to the end.  Bug 270392, r+sr=roc
This commit is contained in:
bzbarsky%mit.edu 2007-01-23 21:42:41 +00:00
Родитель 5bec6fa6ea
Коммит 3e6c065405
2 изменённых файлов: 108 добавлений и 6 удалений

Просмотреть файл

@ -115,7 +115,8 @@ nsSpaceManager::nsSpaceManager(nsIPresShell* aPresShell, nsIFrame* aFrame)
mHaveCachedLeftYMost(PR_TRUE),
mHaveCachedRightYMost(PR_TRUE),
mMaximalLeftYMost(0),
mMaximalRightYMost(0)
mMaximalRightYMost(0),
mCachedBandPosition(nsnull)
{
MOZ_COUNT_CTOR(nsSpaceManager);
mX = mY = 0;
@ -369,8 +370,7 @@ nsSpaceManager::GetBandData(nscoord aYOffset,
aBandData.mTrapezoids[0].mFrame = nsnull;
} else {
// Find the first band that contains the y-offset or is below the y-offset
NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
BandRect* band = mBandList.Head();
BandRect* band = GuessBandWithTopAbove(y);
aBandData.mCount = 0;
while (nsnull != band) {
@ -424,6 +424,37 @@ nsSpaceManager::GetNextBand(const BandRect* aBandRect) const
return nsnull;
}
/**
* Skips to the start of the previous band.
*
* @param aBandRect The first rect within a band
* @returns The start of the previous band, or nsnull of this is the first band.
*/
nsSpaceManager::BandRect*
nsSpaceManager::GetPrevBand(const BandRect* aBandRect) const
{
NS_ASSERTION(aBandRect->Prev() == &mBandList ||
aBandRect->Prev()->mBottom <= aBandRect->mTop,
"aBandRect should be first rect within its band");
BandRect* prev = aBandRect->Prev();
nscoord topOfBand = prev->mTop;
while (prev != &mBandList) {
// Check whether the prev rect is part of the same band
if (prev->mTop != topOfBand) {
// We found the beginning of this band
return (BandRect*)aBandRect;
}
aBandRect = prev;
prev = aBandRect->Prev();
}
// No bands left
return nsnull;
}
/**
* Divides the current band into two vertically
*
@ -514,6 +545,11 @@ nsSpaceManager::JoinBands(BandRect* aBand, BandRect* aPrevBand)
{
if (CanJoinBands(aBand, aPrevBand)) {
BandRect* startOfNextBand = aBand;
// We're going to be removing aPrevBand, so if mCachedBandPosition points
// to it just advance it to startOfNextBand.
if (mCachedBandPosition == aPrevBand) {
SetCachedBandPosition(startOfNextBand);
}
while (aPrevBand != startOfNextBand) {
// Adjust the top of the band we're keeping, and then move to the next
@ -524,6 +560,8 @@ nsSpaceManager::JoinBands(BandRect* aBand, BandRect* aPrevBand)
// Delete the rect from the previous band
BandRect* next = aPrevBand->Next();
NS_ASSERTION(mCachedBandPosition != aPrevBand,
"Removing mCachedBandPosition BandRect?");
aPrevBand->Remove();
delete aPrevBand;
aPrevBand = next;
@ -571,6 +609,9 @@ nsSpaceManager::AddRectToBand(BandRect* aBand, BandRect* aBandRect)
// No, the new rect is completely to the left of the existing rect
// (case #1). Insert a new rect
aBand->InsertBefore(aBandRect);
if (mCachedBandPosition == aBand) {
SetCachedBandPosition(aBandRect);
}
return;
}
@ -602,6 +643,10 @@ nsSpaceManager::AddRectToBand(BandRect* aBand, BandRect* aBandRect)
aBandRect->mRight = aBand->mLeft;
aBand->InsertBefore(aBandRect);
if (mCachedBandPosition == aBand) {
SetCachedBandPosition(aBandRect);
}
// Mark the existing rect as shared
aBand->AddFrame(aBandRect->mFrame);
return;
@ -675,7 +720,8 @@ nsSpaceManager::AddRectToBand(BandRect* aBand, BandRect* aBandRect)
}
} while (aBand->mTop == topOfBand);
// Insert a new rect
// Insert a new rect. This is an insertion at the _end_ of the band, so we
// absolutely do not want to set mCachedBandPosition to aBandRect here.
aBand->InsertBefore(aBandRect);
}
@ -714,12 +760,14 @@ nsSpaceManager::InsertBandRect(BandRect* aBandRect)
nscoord yMost;
if (!YMost(yMost) || (aBandRect->mTop >= yMost)) {
mBandList.Append(aBandRect);
SetCachedBandPosition(aBandRect);
return;
}
// Examine each band looking for a band that intersects this rect
NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
BandRect* band = mBandList.Head();
// First guess a band whose top is above aBandRect->mTop. We know
// aBandRect won't overlap any bands before that one.
BandRect* band = GuessBandWithTopAbove(aBandRect->mTop);
while (nsnull != band) {
// Compare the top edge of this rect with the top edge of the band
@ -730,6 +778,7 @@ nsSpaceManager::InsertBandRect(BandRect* aBandRect)
// Case #1. This rect is completely above the band, so insert a
// new band before the current band
band->InsertBefore(aBandRect);
SetCachedBandPosition(aBandRect);
break; // we're all done
}
@ -774,6 +823,7 @@ nsSpaceManager::InsertBandRect(BandRect* aBandRect)
if (aBandRect->mBottom == band->mBottom) {
// Add the rect to the band
SetCachedBandPosition(band); // Do this before AddRectToBand
AddRectToBand(band, aBandRect);
break;
@ -795,6 +845,7 @@ nsSpaceManager::InsertBandRect(BandRect* aBandRect)
if (nsnull == band) {
// Append a new bottommost band
mBandList.Append(aBandRect);
SetCachedBandPosition(aBandRect);
break;
}
}
@ -916,6 +967,9 @@ nsSpaceManager::RemoveRegion(nsIFrame* aFrame)
} else {
band = nsnull;
}
if (mCachedBandPosition == rect) {
SetCachedBandPosition(band);
}
}
delete rect;
rect = next;
@ -938,6 +992,9 @@ nsSpaceManager::RemoveRegion(nsIFrame* aFrame)
if (prevRect == band) {
// the rect we're deleting is the start of the band
band = rect;
if (mCachedBandPosition == prevRect) {
SetCachedBandPosition(band);
}
}
delete prevRect;
}
@ -962,6 +1019,9 @@ nsSpaceManager::RemoveRegion(nsIFrame* aFrame)
prevFoundMatchingRect = foundMatchingRect;
prevBand = band;
band = (rect == &mBandList) ? nsnull : rect;
if (!mCachedBandPosition) {
SetCachedBandPosition(band);
}
}
}
@ -1273,6 +1333,27 @@ nsSpaceManager::ClearFloats(nscoord aY, PRUint8 aBreakType)
return bottom;
}
nsSpaceManager::BandRect*
nsSpaceManager::GuessBandWithTopAbove(nscoord aYOffset) const
{
NS_ASSERTION(!mBandList.IsEmpty(), "no bands");
BandRect* band = nsnull;
if (mCachedBandPosition) {
band = mCachedBandPosition;
// Now seek backward so that we're guaranteed to be the topmost
// band which might contain the y-offset or be below it.
while (band && band->mTop > aYOffset) {
band = GetPrevBand(band);
}
}
if (band) {
return band;
}
return mBandList.Head();
}
/////////////////////////////////////////////////////////////////////////////
// FrameInfo

Просмотреть файл

@ -453,6 +453,10 @@ protected:
// rects for right floats. Only makes
// sense when mHaveCachedLeftYMost is
// true.
// We keep track of the last BandRect* we worked with so that we can
// make use of locality of reference in situations where people want
// to do a bunch of operations in a row.
BandRect* mCachedBandPosition;
protected:
FrameInfo* GetFrameInfoFor(nsIFrame* aFrame);
@ -463,6 +467,7 @@ protected:
void ClearBandRects();
BandRect* GetNextBand(const BandRect* aBandRect) const;
BandRect* GetPrevBand(const BandRect* aBandRect) const;
void DivideBand(BandRect* aBand, nscoord aBottom);
PRBool CanJoinBands(BandRect* aBand, BandRect* aPrevBand);
PRBool JoinBands(BandRect* aBand, BandRect* aPrevBand);
@ -474,6 +479,22 @@ protected:
const nsSize& aMaxSize,
nsBandData& aAvailableSpace) const;
// Return a band guaranteed to have its top at or above aYOffset or the first
// band if there is no band with its top above aYOffset. This method will
// use mCachedBandPosition to maybe get such a band that's not too far up.
// This function should not be called if there are no bands.
// This function never returns null.
BandRect* GuessBandWithTopAbove(nscoord aYOffset) const;
void SetCachedBandPosition(BandRect* aBandRect) {
NS_ASSERTION(!aBandRect ||
aBandRect == mBandList.Head() ||
aBandRect->Prev()->mBottom != aBandRect->mBottom,
"aBandRect should be first rect within its band");
mCachedBandPosition = aBandRect;
}
private:
static PRInt32 sCachedSpaceManagerCount;
static void* sCachedSpaceManagers[NS_SPACE_MANAGER_CACHE_SIZE];