Bug 407889. Reduce dynamic memory allocations by putting nsDisplayListBuilder's per-presshell state in an nsAutoTArray. r+sr=mats

This commit is contained in:
roc+@cs.cmu.edu 2008-01-03 17:53:01 -08:00
parent e8fc029ca5
commit 95e3dcb532
2 changed files with 54 additions and 45 deletions

View File

@ -132,9 +132,10 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
}
nsDisplayListBuilder::~nsDisplayListBuilder() {
for (PRUint32 i = 0; i < mFramesMarkedForDisplay.Length(); ++i) {
UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
}
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
"All frames should have been unmarked");
NS_ASSERTION(mPresShellStates.Length() == 0,
"All presshells should have been exited");
PL_FreeArenaPool(&mPool);
PL_FinishArenaPool(&mPool);
@ -142,57 +143,58 @@ nsDisplayListBuilder::~nsDisplayListBuilder() {
nsICaret *
nsDisplayListBuilder::GetCaret() {
NS_ASSERTION(mCaretStates.Length() > 0, "Not enough presshells");
nsIFrame* frame = GetCaretFrame();
if (!frame) {
return nsnull;
}
nsIPresShell* shell = frame->PresContext()->PresShell();
nsCOMPtr<nsICaret> caret;
shell->GetCaret(getter_AddRefs(caret));
CurrentPresShellState()->mPresShell->GetCaret(getter_AddRefs(caret));
return caret;
}
void
nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
const nsRect& aDirtyRect) {
PresShellState* state = mPresShellStates.AppendElement();
if (!state)
return;
state->mPresShell = aReferenceFrame->PresContext()->PresShell();
state->mCaretFrame = nsnull;
state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
if (!mBuildCaret)
return;
nsIPresShell* shell = aReferenceFrame->PresContext()->PresShell();
nsCOMPtr<nsICaret> caret;
shell->GetCaret(getter_AddRefs(caret));
nsIFrame* frame = caret->GetCaretFrame();
state->mPresShell->GetCaret(getter_AddRefs(caret));
state->mCaretFrame = caret->GetCaretFrame();
if (frame) {
if (state->mCaretFrame) {
// Check if the dirty rect intersects with the caret's dirty rect.
nsRect caretRect =
caret->GetCaretRect() + frame->GetOffsetTo(aReferenceFrame);
caret->GetCaretRect() + state->mCaretFrame->GetOffsetTo(aReferenceFrame);
if (caretRect.Intersects(aDirtyRect)) {
// Okay, our rects intersect, let's mark the frame and all of its ancestors.
mFramesMarkedForDisplay.AppendElement(frame);
MarkFrameForDisplay(frame, nsnull);
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
MarkFrameForDisplay(state->mCaretFrame, nsnull);
}
}
mCaretStates.AppendElement(frame);
}
void
nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
const nsRect& aDirtyRect)
{
if (!mBuildCaret)
if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) {
// Must have not allocated a state for this presshell, presumably due
// to OOM.
return;
}
// Pop the state off.
NS_ASSERTION(mCaretStates.Length() > 0, "Leaving too many PresShell");
NS_ASSERTION(GetCaret() || GetCaretFrame() == nsnull,
"GetCaret and LeavePresShell diagree");
mCaretStates.SetLength(mCaretStates.Length() - 1);
// Unmark and pop off the frames marked for display in this pres shell.
PRUint32 firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
for (PRUint32 i = firstFrameForShell;
i < mFramesMarkedForDisplay.Length(); ++i) {
UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
}
mFramesMarkedForDisplay.SetLength(firstFrameForShell);
mPresShellStates.SetLength(mPresShellStates.Length() - 1);
}
void

View File

@ -226,11 +226,7 @@ public:
* If the caret is currently invisible, this will be null.
*/
nsIFrame* GetCaretFrame() {
if (mBuildCaret) {
NS_ASSERTION(mCaretStates.Length() > 0, "Not enough presshells");
return mCaretStates[mCaretStates.Length() - 1];
}
return nsnull;
return CurrentPresShellState()->mCaretFrame;
}
/**
* Get the caret associated with the current presshell.
@ -290,18 +286,29 @@ private:
// it. Don't let us be heap-allocated!
void* operator new(size_t sz) CPP_THROW_NEW;
nsIFrame* mReferenceFrame;
nsIFrame* mMovingFrame;
nsIFrame* mIgnoreScrollFrame;
PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection;
nsTArray<nsIFrame*> mCaretStates;
nsTArray<nsIFrame*> mFramesMarkedForDisplay;
PRPackedBool mBuildCaret;
PRPackedBool mEventDelivery;
PRPackedBool mIsBackgroundOnly;
PRPackedBool mIsAtRootOfPseudoStackingContext;
PRPackedBool mPaintAllFrames;
struct PresShellState {
nsIPresShell* mPresShell;
nsIFrame* mCaretFrame;
PRUint32 mFirstFrameMarkedForDisplay;
};
PresShellState* CurrentPresShellState() {
NS_ASSERTION(mPresShellStates.Length() > 0,
"Someone forgot to enter a presshell");
return &mPresShellStates[mPresShellStates.Length() - 1];
}
nsIFrame* mReferenceFrame;
nsIFrame* mMovingFrame;
nsIFrame* mIgnoreScrollFrame;
PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection;
nsAutoTArray<PresShellState,8> mPresShellStates;
nsAutoTArray<nsIFrame*,100> mFramesMarkedForDisplay;
PRPackedBool mBuildCaret;
PRPackedBool mEventDelivery;
PRPackedBool mIsBackgroundOnly;
PRPackedBool mIsAtRootOfPseudoStackingContext;
PRPackedBool mPaintAllFrames;
};
class nsDisplayItem;