From d393d4d00caebfb662cc1cfecfe15aef96d52e72 Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Fri, 4 Jan 2008 01:53:01 +0000 Subject: [PATCH] Bug 407889. Reduce dynamic memory allocations by putting nsDisplayListBuilder's per-presshell state in an nsAutoTArray. r+sr=mats git-svn-id: svn://10.0.0.236/trunk@242341 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/nsDisplayList.cpp | 58 ++++++++++++++------------- mozilla/layout/base/nsDisplayList.h | 41 +++++++++++-------- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/mozilla/layout/base/nsDisplayList.cpp b/mozilla/layout/base/nsDisplayList.cpp index 5f0cda53186..1aa87977ed2 100644 --- a/mozilla/layout/base/nsDisplayList.cpp +++ b/mozilla/layout/base/nsDisplayList.cpp @@ -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 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 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 diff --git a/mozilla/layout/base/nsDisplayList.h b/mozilla/layout/base/nsDisplayList.h index b52688e26d7..9b549040d97 100644 --- a/mozilla/layout/base/nsDisplayList.h +++ b/mozilla/layout/base/nsDisplayList.h @@ -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 mBoundingSelection; - nsTArray mCaretStates; - nsTArray 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 mBoundingSelection; + nsAutoTArray mPresShellStates; + nsAutoTArray mFramesMarkedForDisplay; + PRPackedBool mBuildCaret; + PRPackedBool mEventDelivery; + PRPackedBool mIsBackgroundOnly; + PRPackedBool mIsAtRootOfPseudoStackingContext; + PRPackedBool mPaintAllFrames; }; class nsDisplayItem;