зеркало из https://github.com/mozilla/gecko-dev.git
Bug 730769 - Make nsLineBox use a frame hash table for lines with many frames. part=2/2 r=bz
This commit is contained in:
Родитель
170ef239c4
Коммит
7213c84c26
|
@ -2671,16 +2671,14 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
|
||||||
}
|
}
|
||||||
// when aFromContainer is 'this', then aLine->LastChild()'s next sibling
|
// when aFromContainer is 'this', then aLine->LastChild()'s next sibling
|
||||||
// is already set correctly.
|
// is already set correctly.
|
||||||
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
aLine->NoteFrameAdded(frame);
|
||||||
|
|
||||||
PRInt32 fromLineChildCount = fromLine->GetChildCount();
|
if (fromLine->GetChildCount() > 1) {
|
||||||
if (0 != --fromLineChildCount) {
|
|
||||||
// Mark line dirty now that we pulled a child
|
// Mark line dirty now that we pulled a child
|
||||||
fromLine->SetChildCount(fromLineChildCount);
|
fromLine->NoteFrameRemoved(frame);
|
||||||
fromLine->MarkDirty();
|
fromLine->MarkDirty();
|
||||||
fromLine->mFirstChild = newFirstChild;
|
fromLine->mFirstChild = newFirstChild;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Free up the fromLine now that it's empty
|
// Free up the fromLine now that it's empty
|
||||||
// Its bounds might need to be redrawn, though.
|
// Its bounds might need to be redrawn, though.
|
||||||
// XXX WHY do we invalidate the bounds AND the combined area? doesn't
|
// XXX WHY do we invalidate the bounds AND the combined area? doesn't
|
||||||
|
@ -3305,7 +3303,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||||
|
|
||||||
// Push continuation to a new line, but only if we actually made one.
|
// Push continuation to a new line, but only if we actually made one.
|
||||||
if (madeContinuation) {
|
if (madeContinuation) {
|
||||||
nsLineBox* line = NewLineBox(nextFrame, 1, true);
|
nsLineBox* line = NewLineBox(nextFrame, true);
|
||||||
NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY);
|
||||||
mLines.after_insert(aLine, line);
|
mLines.after_insert(aLine, line);
|
||||||
}
|
}
|
||||||
|
@ -3976,7 +3974,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
||||||
mFrames.InsertFrame(nsnull, aFrame, newFrame);
|
mFrames.InsertFrame(nsnull, aFrame, newFrame);
|
||||||
|
|
||||||
if (aLine) {
|
if (aLine) {
|
||||||
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
aLine->NoteFrameAdded(newFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
aMadeNewFrame = true;
|
aMadeNewFrame = true;
|
||||||
|
@ -4099,12 +4097,11 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Put frames being split out into their own line
|
// Put frames being split out into their own line
|
||||||
nsLineBox* newLine = NewLineBox(aFrame, pushCount, false);
|
nsLineBox* newLine = NewLineBox(aLine, aFrame, pushCount);
|
||||||
if (!newLine) {
|
if (!newLine) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
mLines.after_insert(aLine, newLine);
|
mLines.after_insert(aLine, newLine);
|
||||||
aLine->SetChildCount(aLine->GetChildCount() - pushCount);
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (gReallyNoisyReflow) {
|
if (gReallyNoisyReflow) {
|
||||||
newLine->List(stdout, gNoiseIndent+1);
|
newLine->List(stdout, gNoiseIndent+1);
|
||||||
|
@ -4920,12 +4917,11 @@ nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
|
||||||
PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
|
PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
|
||||||
if (rem) {
|
if (rem) {
|
||||||
// Split the line in two where the frame(s) are being inserted.
|
// Split the line in two where the frame(s) are being inserted.
|
||||||
nsLineBox* line = NewLineBox(aPrevSibling->GetNextSibling(), rem, false);
|
nsLineBox* line = NewLineBox(prevSibLine, aPrevSibling->GetNextSibling(), rem);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
lineList->after_insert(prevSibLine, line);
|
lineList->after_insert(prevSibLine, line);
|
||||||
prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
|
|
||||||
// Mark prevSibLine dirty and as needing textrun invalidation, since
|
// Mark prevSibLine dirty and as needing textrun invalidation, since
|
||||||
// we may be breaking up text in the line. Its previous line may also
|
// we may be breaking up text in the line. Its previous line may also
|
||||||
// need to be invalidated because it may be able to pull some text up.
|
// need to be invalidated because it may be able to pull some text up.
|
||||||
|
@ -4966,7 +4962,7 @@ nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
|
||||||
(aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
|
(aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
|
||||||
// Create a new line for the frame and add its line to the line
|
// Create a new line for the frame and add its line to the line
|
||||||
// list.
|
// list.
|
||||||
nsLineBox* line = NewLineBox(newFrame, 1, isBlock);
|
nsLineBox* line = NewLineBox(newFrame, isBlock);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
@ -4982,7 +4978,7 @@ nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prevSibLine->SetChildCount(prevSibLine->GetChildCount() + 1);
|
prevSibLine->NoteFrameAdded(newFrame);
|
||||||
// We're adding inline content to prevSibLine, so we need to mark it
|
// We're adding inline content to prevSibLine, so we need to mark it
|
||||||
// dirty, ensure its textruns are recomputed, and possibly do the same
|
// dirty, ensure its textruns are recomputed, and possibly do the same
|
||||||
// to its previous line since that line may be able to pull content up.
|
// to its previous line since that line may be able to pull content up.
|
||||||
|
@ -5504,9 +5500,7 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the child count of the line to be accurate
|
// Update the child count of the line to be accurate
|
||||||
PRInt32 lineChildCount = line->GetChildCount();
|
line->NoteFrameRemoved(aDeletedFrame);
|
||||||
lineChildCount--;
|
|
||||||
line->SetChildCount(lineChildCount);
|
|
||||||
|
|
||||||
// Destroy frame; capture its next continuation first in case we need
|
// Destroy frame; capture its next continuation first in case we need
|
||||||
// to destroy that too.
|
// to destroy that too.
|
||||||
|
@ -5533,7 +5527,7 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags)
|
||||||
|
|
||||||
bool haveAdvancedToNextLine = false;
|
bool haveAdvancedToNextLine = false;
|
||||||
// If line is empty, remove it now.
|
// If line is empty, remove it now.
|
||||||
if (0 == lineChildCount) {
|
if (0 == line->GetChildCount()) {
|
||||||
#ifdef NOISY_REMOVE_FRAME
|
#ifdef NOISY_REMOVE_FRAME
|
||||||
printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
|
printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
|
||||||
searchingOverflowList?"overflow":"normal", line.get());
|
searchingOverflowList?"overflow":"normal", line.get());
|
||||||
|
@ -5686,12 +5680,10 @@ nsBlockFrame::StealFrame(nsPresContext* aPresContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register removal with the line boxes
|
// Register removal with the line boxes
|
||||||
PRInt32 count = line->GetChildCount();
|
line->NoteFrameRemoved(frame);
|
||||||
line->SetChildCount(--count);
|
if (line->GetChildCount() > 0) {
|
||||||
if (count > 0) {
|
|
||||||
line->MarkDirty();
|
line->MarkDirty();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Remove the line box
|
// Remove the line box
|
||||||
nsLineBox* lineBox = line;
|
nsLineBox* lineBox = line;
|
||||||
if (searchingOverflowList) {
|
if (searchingOverflowList) {
|
||||||
|
@ -5710,8 +5702,7 @@ nsBlockFrame::StealFrame(nsPresContext* aPresContext,
|
||||||
line_end = mLines.end();
|
line_end = mLines.end();
|
||||||
line = line_end;
|
line = line_end;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
line = mLines.erase(line);
|
line = mLines.erase(line);
|
||||||
}
|
}
|
||||||
lineBox->Destroy(aPresContext->PresShell());
|
lineBox->Destroy(aPresContext->PresShell());
|
||||||
|
|
|
@ -354,8 +354,11 @@ protected:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock) {
|
nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
|
||||||
return NS_NewLineBox(PresContext()->PresShell(), aFrame, aCount, aIsBlock);
|
return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);
|
||||||
|
}
|
||||||
|
nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, PRInt32 aCount) {
|
||||||
|
return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount);
|
||||||
}
|
}
|
||||||
void FreeLineBox(nsLineBox* aLine) {
|
void FreeLineBox(nsLineBox* aLine) {
|
||||||
aLine->Destroy(PresContext()->PresShell());
|
aLine->Destroy(PresContext()->PresShell());
|
||||||
|
|
|
@ -55,6 +55,11 @@ static PRInt32 ctorCount;
|
||||||
PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
|
PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
// static nsLineBox constant; initialized in the header file.
|
||||||
|
const PRUint32 nsLineBox::kMinChildCountForHashtable;
|
||||||
|
#endif
|
||||||
|
|
||||||
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
|
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
|
||||||
: mFirstChild(aFrame),
|
: mFirstChild(aFrame),
|
||||||
mBounds(0, 0, 0, 0),
|
mBounds(0, 0, 0, 0),
|
||||||
|
@ -76,7 +81,7 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
|
||||||
#if NS_STYLE_CLEAR_NONE > 0
|
#if NS_STYLE_CLEAR_NONE > 0
|
||||||
mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
|
mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
|
||||||
#endif
|
#endif
|
||||||
SetChildCount(aCount);
|
mChildCount = aCount;
|
||||||
MarkDirty();
|
MarkDirty();
|
||||||
mFlags.mBlock = aIsBlock;
|
mFlags.mBlock = aIsBlock;
|
||||||
}
|
}
|
||||||
|
@ -84,14 +89,88 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, bool aIsBlock)
|
||||||
nsLineBox::~nsLineBox()
|
nsLineBox::~nsLineBox()
|
||||||
{
|
{
|
||||||
MOZ_COUNT_DTOR(nsLineBox);
|
MOZ_COUNT_DTOR(nsLineBox);
|
||||||
|
if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
|
||||||
|
delete mFrames;
|
||||||
|
}
|
||||||
Cleanup();
|
Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsLineBox*
|
nsLineBox*
|
||||||
NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
|
NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame, bool aIsBlock)
|
||||||
PRInt32 aCount, bool aIsBlock)
|
|
||||||
{
|
{
|
||||||
return new (aPresShell)nsLineBox(aFrame, aCount, aIsBlock);
|
return new (aPresShell) nsLineBox(aFrame, 1, aIsBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsLineBox*
|
||||||
|
NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
|
||||||
|
nsIFrame* aFrame, PRInt32 aCount)
|
||||||
|
{
|
||||||
|
nsLineBox* newLine = new (aPresShell) nsLineBox(aFrame, aCount, false);
|
||||||
|
if (newLine) {
|
||||||
|
newLine->NoteFramesMovedFrom(aFromLine);
|
||||||
|
}
|
||||||
|
return newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsLineBox::StealHashTableFrom(nsLineBox* aFromLine, PRUint32 aFromLineNewCount)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mFlags.mHasHashedFrames);
|
||||||
|
MOZ_ASSERT(GetChildCount() >= PRInt32(aFromLineNewCount));
|
||||||
|
mFrames = aFromLine->mFrames;
|
||||||
|
mFlags.mHasHashedFrames = 1;
|
||||||
|
aFromLine->mFlags.mHasHashedFrames = 0;
|
||||||
|
aFromLine->mChildCount = aFromLineNewCount;
|
||||||
|
// remove aFromLine's frames that aren't on this line
|
||||||
|
nsIFrame* f = aFromLine->mFirstChild;
|
||||||
|
for (PRUint32 i = 0; i < aFromLineNewCount; f = f->GetNextSibling(), ++i) {
|
||||||
|
mFrames->RemoveEntry(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine)
|
||||||
|
{
|
||||||
|
PRUint32 fromCount = aFromLine->GetChildCount();
|
||||||
|
PRUint32 toCount = GetChildCount();
|
||||||
|
MOZ_ASSERT(toCount <= fromCount, "moved more frames than aFromLine has");
|
||||||
|
PRUint32 fromNewCount = fromCount - toCount;
|
||||||
|
if (NS_LIKELY(!aFromLine->mFlags.mHasHashedFrames)) {
|
||||||
|
aFromLine->mChildCount = fromNewCount;
|
||||||
|
MOZ_ASSERT(toCount < kMinChildCountForHashtable);
|
||||||
|
} else if (fromNewCount < kMinChildCountForHashtable) {
|
||||||
|
// aFromLine has a hash table but will not have it after moving the frames
|
||||||
|
// so this line can steal the hash table if it needs it.
|
||||||
|
if (toCount >= kMinChildCountForHashtable) {
|
||||||
|
StealHashTableFrom(aFromLine, fromNewCount);
|
||||||
|
} else {
|
||||||
|
delete aFromLine->mFrames;
|
||||||
|
aFromLine->mFlags.mHasHashedFrames = 0;
|
||||||
|
aFromLine->mChildCount = fromNewCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// aFromLine still needs a hash table.
|
||||||
|
if (toCount < kMinChildCountForHashtable) {
|
||||||
|
// remove the moved frames from it
|
||||||
|
nsIFrame* f = mFirstChild;
|
||||||
|
for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
|
||||||
|
aFromLine->mFrames->RemoveEntry(f);
|
||||||
|
}
|
||||||
|
} else if (toCount <= fromNewCount) {
|
||||||
|
// This line needs a hash table, allocate a hash table for it since that
|
||||||
|
// means fewer hash ops.
|
||||||
|
nsIFrame* f = mFirstChild;
|
||||||
|
for (PRUint32 i = 0; i < toCount; f = f->GetNextSibling(), ++i) {
|
||||||
|
aFromLine->mFrames->RemoveEntry(f); // toCount RemoveEntry
|
||||||
|
}
|
||||||
|
SwitchToHashtable(); // toCount PutEntry
|
||||||
|
} else {
|
||||||
|
// This line needs a hash table, but it's fewer hash ops to steal
|
||||||
|
// aFromLine's hash table and allocate a new hash table for that line.
|
||||||
|
StealHashTableFrom(aFromLine, fromNewCount); // fromNewCount RemoveEntry
|
||||||
|
aFromLine->SwitchToHashtable(); // fromNewCount PutEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
||||||
|
@ -102,21 +181,11 @@ nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
|
||||||
return aPresShell->AllocateMisc(sz);
|
return aPresShell->AllocateMisc(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded delete operator. Doesn't actually free the memory, because we
|
|
||||||
// use an arena
|
|
||||||
void
|
|
||||||
nsLineBox::operator delete(void* aPtr, size_t sz)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsLineBox::Destroy(nsIPresShell* aPresShell)
|
nsLineBox::Destroy(nsIPresShell* aPresShell)
|
||||||
{
|
{
|
||||||
// Destroy the object. This won't actually free the memory, though
|
this->nsLineBox::~nsLineBox();
|
||||||
delete this;
|
aPresShell->FreeMisc(sizeof(*this), this);
|
||||||
|
|
||||||
// Have the pres shell recycle the memory
|
|
||||||
aPresShell->FreeMisc(sizeof(*this), (void*)this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -365,10 +434,18 @@ nsLineBox::RFindLineContaining(nsIFrame* aFrame,
|
||||||
PRInt32* aFrameIndexInLine)
|
PRInt32* aFrameIndexInLine)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aFrame, "null ptr");
|
NS_PRECONDITION(aFrame, "null ptr");
|
||||||
|
|
||||||
nsIFrame* curFrame = aLastFrameBeforeEnd;
|
nsIFrame* curFrame = aLastFrameBeforeEnd;
|
||||||
while (aBegin != aEnd) {
|
while (aBegin != aEnd) {
|
||||||
--aEnd;
|
--aEnd;
|
||||||
NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame");
|
NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame");
|
||||||
|
if (NS_UNLIKELY(aEnd->mFlags.mHasHashedFrames) &&
|
||||||
|
!aEnd->Contains(aFrame)) {
|
||||||
|
if (aEnd->mFirstChild) {
|
||||||
|
curFrame = aEnd->mFirstChild->GetPrevSibling();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// i is the index of curFrame in aEnd
|
// i is the index of curFrame in aEnd
|
||||||
PRInt32 i = aEnd->GetChildCount() - 1;
|
PRInt32 i = aEnd->GetChildCount() - 1;
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
|
@ -379,6 +456,7 @@ nsLineBox::RFindLineContaining(nsIFrame* aFrame,
|
||||||
--i;
|
--i;
|
||||||
curFrame = curFrame->GetPrevSibling();
|
curFrame = curFrame->GetPrevSibling();
|
||||||
}
|
}
|
||||||
|
MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!");
|
||||||
}
|
}
|
||||||
*aFrameIndexInLine = -1;
|
*aFrameIndexInLine = -1;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -182,9 +182,21 @@ protected:
|
||||||
need to rearrange the mBits bitfield;
|
need to rearrange the mBits bitfield;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Funtion to create a line box
|
/**
|
||||||
|
* Function to create a line box and initialize it with a single frame.
|
||||||
|
* If the frame was moved from another line then you're responsible
|
||||||
|
* for notifying that line using NoteFrameRemoved(). Alternatively,
|
||||||
|
* it's better to use the next function that does that for you in an
|
||||||
|
* optimal way.
|
||||||
|
*/
|
||||||
nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
|
nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
|
||||||
PRInt32 aCount, bool aIsBlock);
|
bool aIsBlock);
|
||||||
|
/**
|
||||||
|
* Function to create a line box and initialize it with aCount frames
|
||||||
|
* that are currently on aFromLine.
|
||||||
|
*/
|
||||||
|
nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
|
||||||
|
nsIFrame* aFrame, PRInt32 aCount);
|
||||||
|
|
||||||
class nsLineList;
|
class nsLineList;
|
||||||
|
|
||||||
|
@ -232,13 +244,14 @@ private:
|
||||||
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
// Overloaded new operator. Uses an arena (which comes from the presShell)
|
||||||
// to perform the allocation.
|
// to perform the allocation.
|
||||||
void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
|
void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
|
||||||
void operator delete(void* aPtr, size_t sz);
|
void operator delete(void* aPtr, size_t sz) MOZ_DELETE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Use these two functions to allocate and destroy line boxes
|
// Use these functions to allocate and destroy line boxes
|
||||||
friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
|
friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
|
||||||
PRInt32 aCount, bool aIsBlock);
|
bool aIsBlock);
|
||||||
|
friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
|
||||||
|
nsIFrame* aFrame, PRInt32 aCount);
|
||||||
void Destroy(nsIPresShell* aPresShell);
|
void Destroy(nsIPresShell* aPresShell);
|
||||||
|
|
||||||
// mBlock bit
|
// mBlock bit
|
||||||
|
@ -284,7 +297,6 @@ public:
|
||||||
|
|
||||||
// mImpactedByFloat bit
|
// mImpactedByFloat bit
|
||||||
void SetLineIsImpactedByFloat(bool aValue) {
|
void SetLineIsImpactedByFloat(bool aValue) {
|
||||||
NS_ASSERTION((false==aValue || true==aValue), "somebody is playing fast and loose with bools and bits!");
|
|
||||||
mFlags.mImpactedByFloat = aValue;
|
mFlags.mImpactedByFloat = aValue;
|
||||||
}
|
}
|
||||||
bool IsImpactedByFloat() const {
|
bool IsImpactedByFloat() const {
|
||||||
|
@ -293,7 +305,6 @@ public:
|
||||||
|
|
||||||
// mLineWrapped bit
|
// mLineWrapped bit
|
||||||
void SetLineWrapped(bool aOn) {
|
void SetLineWrapped(bool aOn) {
|
||||||
NS_ASSERTION((false==aOn || true==aOn), "somebody is playing fast and loose with bools and bits!");
|
|
||||||
mFlags.mLineWrapped = aOn;
|
mFlags.mLineWrapped = aOn;
|
||||||
}
|
}
|
||||||
bool IsLineWrapped() const {
|
bool IsLineWrapped() const {
|
||||||
|
@ -302,7 +313,6 @@ public:
|
||||||
|
|
||||||
// mInvalidateTextRuns bit
|
// mInvalidateTextRuns bit
|
||||||
void SetInvalidateTextRuns(bool aOn) {
|
void SetInvalidateTextRuns(bool aOn) {
|
||||||
NS_ASSERTION((false==aOn || true==aOn), "somebody is playing fast and loose with bools and bits!");
|
|
||||||
mFlags.mInvalidateTextRuns = aOn;
|
mFlags.mInvalidateTextRuns = aOn;
|
||||||
}
|
}
|
||||||
bool GetInvalidateTextRuns() const {
|
bool GetInvalidateTextRuns() const {
|
||||||
|
@ -344,20 +354,76 @@ public:
|
||||||
return mFlags.mHadFloatPushed;
|
return mFlags.mHadFloatPushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Add a hash table for fast lookup when the line has more frames than this.
|
||||||
|
static const PRUint32 kMinChildCountForHashtable = 200;
|
||||||
|
|
||||||
// mChildCount value
|
/**
|
||||||
|
* Take ownership of aFromLine's hash table and remove the frames that
|
||||||
|
* stay on aFromLine from it, i.e. aFromLineNewCount frames starting with
|
||||||
|
* mFirstChild. This method is used to optimize moving a large number
|
||||||
|
* of frames from one line to the next.
|
||||||
|
*/
|
||||||
|
void StealHashTableFrom(nsLineBox* aFromLine, PRUint32 aFromLineNewCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the equivalent of this->NoteFrameAdded and aFromLine->NoteFrameRemoved
|
||||||
|
* for each frame on this line, but in a optimized way.
|
||||||
|
*/
|
||||||
|
void NoteFramesMovedFrom(nsLineBox* aFromLine);
|
||||||
|
|
||||||
|
void SwitchToHashtable()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mFlags.mHasHashedFrames);
|
||||||
|
PRUint32 count = GetChildCount();
|
||||||
|
mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >();
|
||||||
|
mFlags.mHasHashedFrames = 1;
|
||||||
|
PRUint32 minSize =
|
||||||
|
NS_MAX(kMinChildCountForHashtable, PRUint32(PL_DHASH_MIN_SIZE));
|
||||||
|
mFrames->Init(NS_MAX(count, minSize));
|
||||||
|
for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
|
||||||
|
mFrames->PutEntry(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SwitchToCounter() {
|
||||||
|
MOZ_ASSERT(mFlags.mHasHashedFrames);
|
||||||
|
PRUint32 count = GetChildCount();
|
||||||
|
delete mFrames;
|
||||||
|
mFlags.mHasHashedFrames = 0;
|
||||||
|
mChildCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
PRInt32 GetChildCount() const {
|
PRInt32 GetChildCount() const {
|
||||||
return (PRInt32) mFlags.mChildCount;
|
return NS_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() : mChildCount;
|
||||||
}
|
}
|
||||||
void SetChildCount(PRInt32 aNewCount) {
|
|
||||||
if (aNewCount < 0) {
|
/**
|
||||||
NS_WARNING("negative child count");
|
* Register that aFrame is now on this line.
|
||||||
aNewCount = 0;
|
*/
|
||||||
|
void NoteFrameAdded(nsIFrame* aFrame) {
|
||||||
|
if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
|
||||||
|
mFrames->PutEntry(aFrame);
|
||||||
|
} else {
|
||||||
|
if (++mChildCount >= kMinChildCountForHashtable) {
|
||||||
|
SwitchToHashtable();
|
||||||
}
|
}
|
||||||
if (aNewCount > LINE_MAX_CHILD_COUNT) {
|
|
||||||
aNewCount = LINE_MAX_CHILD_COUNT;
|
|
||||||
}
|
}
|
||||||
mFlags.mChildCount = aNewCount;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register that aFrame is not on this line anymore.
|
||||||
|
*/
|
||||||
|
void NoteFrameRemoved(nsIFrame* aFrame) {
|
||||||
|
MOZ_ASSERT(GetChildCount() > 0);
|
||||||
|
if (NS_UNLIKELY(mFlags.mHasHashedFrames)) {
|
||||||
|
mFrames->RemoveEntry(aFrame);
|
||||||
|
if (mFrames->Count() < kMinChildCountForHashtable) {
|
||||||
|
SwitchToCounter();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
--mChildCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mBreakType value
|
// mBreakType value
|
||||||
|
@ -473,10 +539,13 @@ public:
|
||||||
nsIFrame* LastChild() const;
|
nsIFrame* LastChild() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
PRInt32 IndexOf(nsIFrame* aFrame) const;
|
PRInt32 IndexOf(nsIFrame* aFrame) const;
|
||||||
|
public:
|
||||||
|
|
||||||
bool Contains(nsIFrame* aFrame) const {
|
bool Contains(nsIFrame* aFrame) const {
|
||||||
return IndexOf(aFrame) >= 0;
|
return NS_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame)
|
||||||
|
: IndexOf(aFrame) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
|
// whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
|
||||||
|
@ -504,6 +573,12 @@ public:
|
||||||
|
|
||||||
nsRect mBounds;
|
nsRect mBounds;
|
||||||
|
|
||||||
|
// mFlags.mHasHashedFrames says which one to use
|
||||||
|
union {
|
||||||
|
nsTHashtable< nsPtrHashKey<nsIFrame> >* mFrames;
|
||||||
|
PRUint32 mChildCount;
|
||||||
|
};
|
||||||
|
|
||||||
struct FlagBits {
|
struct FlagBits {
|
||||||
PRUint32 mDirty : 1;
|
PRUint32 mDirty : 1;
|
||||||
PRUint32 mPreviousMarginDirty : 1;
|
PRUint32 mPreviousMarginDirty : 1;
|
||||||
|
@ -521,10 +596,8 @@ public:
|
||||||
// Indicates that this line *may* have a placeholder for a float
|
// Indicates that this line *may* have a placeholder for a float
|
||||||
// that was pushed to a later column or page.
|
// that was pushed to a later column or page.
|
||||||
PRUint32 mHadFloatPushed : 1;
|
PRUint32 mHadFloatPushed : 1;
|
||||||
|
PRUint32 mHasHashedFrames: 1;
|
||||||
PRUint32 mBreakType : 4;
|
PRUint32 mBreakType : 4;
|
||||||
|
|
||||||
// FIXME: Move this out of FlagBits
|
|
||||||
PRUint32 mChildCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExtraData {
|
struct ExtraData {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче