Bug 655084 - Remove nsWeakFrame's from editor scripts and the nsTextInputListener to improve perf on pages with lots of text widgets. r=ehsan

This commit is contained in:
Randell Jesup 2011-05-21 04:25:27 -04:00
parent 969b71d749
commit f9901669f2
4 changed files with 70 additions and 23 deletions

View File

@ -84,7 +84,6 @@ public:
RestoreSelectionState(nsTextEditorState *aState, nsTextControlFrame *aFrame,
PRInt32 aStart, PRInt32 aEnd)
: mFrame(aFrame),
mWeakFrame(aFrame),
mStart(aStart),
mEnd(aEnd),
mTextEditorState(aState)
@ -92,19 +91,24 @@ public:
}
NS_IMETHOD Run() {
if (mWeakFrame.IsAlive()) {
if (mFrame) {
// SetSelectionRange leads to Selection::AddRange which flushes Layout -
// need to block script to avoid nested PrepareEditor calls (bug 642800).
nsAutoScriptBlocker scriptBlocker;
mFrame->SetSelectionRange(mStart, mEnd);
mTextEditorState->HideSelectionIfBlurred();
}
mTextEditorState->FinishedRestoringSelection();
return NS_OK;
}
// Let the text editor tell us we're no longer relevant - avoids use of nsWeakFrame
void Revoke() {
mFrame = nsnull;
}
private:
nsTextControlFrame* mFrame;
nsWeakFrame mWeakFrame;
PRInt32 mStart;
PRInt32 mEnd;
nsTextEditorState* mTextEditorState;
@ -645,7 +649,7 @@ protected:
protected:
nsWeakFrame mFrame;
nsIFrame* mFrame;
nsITextControlElement* const mTxtCtrlElement;
@ -673,7 +677,8 @@ protected:
*/
nsTextInputListener::nsTextInputListener(nsITextControlElement* aTxtCtrlElement)
: mTxtCtrlElement(aTxtCtrlElement)
: mFrame(nsnull)
, mTxtCtrlElement(aTxtCtrlElement)
, mSelectionWasCollapsed(PR_TRUE)
, mHadUndoItems(PR_FALSE)
, mHadRedoItems(PR_FALSE)
@ -703,7 +708,9 @@ NS_IMETHODIMP
nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel, PRInt16 aReason)
{
PRBool collapsed;
if (!mFrame.IsAlive() || !aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
nsWeakFrame weakFrame = mFrame;
if (!aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
return NS_OK;
// Fire the select event
@ -748,7 +755,7 @@ nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection*
mSelectionWasCollapsed = collapsed;
if (!mFrame.IsAlive() || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
if (!weakFrame.IsAlive() || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
return NS_OK;
return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
@ -799,7 +806,6 @@ DoCommandCallback(const char *aCommand, void *aData)
NS_IMETHODIMP
nsTextInputListener::KeyDown(nsIDOMEvent *aDOMEvent)
{
NS_ENSURE_STATE(mFrame.IsAlive());
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
@ -818,7 +824,6 @@ nsTextInputListener::KeyDown(nsIDOMEvent *aDOMEvent)
NS_IMETHODIMP
nsTextInputListener::KeyPress(nsIDOMEvent *aDOMEvent)
{
NS_ENSURE_STATE(mFrame.IsAlive());
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
@ -837,7 +842,6 @@ nsTextInputListener::KeyPress(nsIDOMEvent *aDOMEvent)
NS_IMETHODIMP
nsTextInputListener::KeyUp(nsIDOMEvent *aDOMEvent)
{
NS_ENSURE_STATE(mFrame.IsAlive());
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
@ -859,8 +863,9 @@ nsTextInputListener::KeyUp(nsIDOMEvent *aDOMEvent)
NS_IMETHODIMP
nsTextInputListener::EditAction()
{
NS_ENSURE_STATE(mFrame.IsAlive());
nsITextControlFrame* frameBase = do_QueryFrame(mFrame.GetFrame());
nsWeakFrame weakFrame = mFrame;
nsITextControlFrame* frameBase = do_QueryFrame(mFrame);
nsTextControlFrame* frame = static_cast<nsTextControlFrame*> (frameBase);
NS_ASSERTION(frame, "Where is our frame?");
//
@ -887,7 +892,7 @@ nsTextInputListener::EditAction()
mHadRedoItems = numRedoItems != 0;
}
if (!mFrame.IsAlive()) {
if (!weakFrame.IsAlive()) {
return NS_OK;
}
@ -916,8 +921,6 @@ nsTextInputListener::EditAction()
nsresult
nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
{
NS_ENSURE_STATE(mFrame.IsAlive());
nsIContent* content = mFrame->GetContent();
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
@ -967,6 +970,7 @@ nsTextInputListener::GetKeyBindings()
nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
: mTextCtrlElement(aOwningElement),
mRestoringSelection(nsnull),
mBoundFrame(nsnull),
mTextListener(nsnull),
mEditorInitialized(PR_FALSE),
@ -1385,8 +1389,13 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
// Restore our selection after being bound to a new frame
if (mSelState) {
nsContentUtils::AddScriptRunner(new RestoreSelectionState(this, mBoundFrame, mSelState->mStart, mSelState->mEnd));
mSelState = nsnull;
if (mRestoringSelection) // paranoia
mRestoringSelection->Revoke();
mRestoringSelection = new RestoreSelectionState(this, mBoundFrame, mSelState->mStart, mSelState->mEnd);
if (mRestoringSelection) {
nsContentUtils::AddScriptRunner(mRestoringSelection);
mSelState = nsnull;
}
}
return rv;
@ -1419,6 +1428,11 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
nsAutoString value;
GetValue(value, PR_TRUE);
if (mRestoringSelection) {
mRestoringSelection->Revoke();
mRestoringSelection = nsnull;
}
// Save our selection state if needed.
// Note that nsTextControlFrame::GetSelectionRange attempts to initialize the
// editor before grabbing the range, and because this is not an acceptable

View File

@ -140,6 +140,8 @@ struct SelectionState;
* frame is bound to the text editor state object.
*/
class RestoreSelectionState;
class nsTextEditorState {
public:
explicit nsTextEditorState(nsITextControlElement* aOwningElement);
@ -213,6 +215,8 @@ public:
void HideSelectionIfBlurred();
private:
friend class RestoreSelectionState;
// not copy constructible
nsTextEditorState(const nsTextEditorState&);
// not assignable
@ -225,6 +229,8 @@ private:
void DestroyEditor();
void Clear();
void FinishedRestoringSelection() { mRestoringSelection = nsnull; }
class InitializationGuard {
public:
explicit InitializationGuard(nsTextEditorState& aState) :
@ -253,6 +259,7 @@ private:
nsITextControlElement* const mTextCtrlElement;
nsRefPtr<nsTextInputSelectionImpl> mSelCon;
nsAutoPtr<SelectionState> mSelState;
RestoreSelectionState* mRestoringSelection;
nsCOMPtr<nsIEditor> mEditor;
nsCOMPtr<nsIContent> mRootNode;
nsCOMPtr<nsIContent> mPlaceholderDiv;

View File

@ -201,6 +201,12 @@ nsTextControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
mScrollEvent.Revoke();
EditorInitializer* initializer = (EditorInitializer*) Properties().Get(TextControlInitializer());
if (initializer) {
initializer->Revoke();
Properties().Delete(TextControlInitializer());
}
// Unbind the text editor state object from the frame. The editor will live
// on, but things like controllers will be released.
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
@ -445,10 +451,17 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
if (initEagerly) {
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"Someone forgot a script blocker?");
if (!nsContentUtils::AddScriptRunner(new EditorInitializer(this))) {
EditorInitializer* initializer = (EditorInitializer*) Properties().Get(TextControlInitializer());
if (initializer) {
initializer->Revoke();
}
initializer = new EditorInitializer(this);
if (!nsContentUtils::AddScriptRunner(initializer)) {
initializer->Revoke(); // paranoia
delete initializer;
return NS_ERROR_OUT_OF_MEMORY;
}
Properties().Set(TextControlInitializer(),initializer);
}
return NS_OK;

View File

@ -180,6 +180,11 @@ public:
NS_DECL_QUERYFRAME
// Temp reference to scriptrunner
// We could make these auto-Revoking via the "delete" entry for safety
NS_DECLARE_FRAME_PROPERTY(TextControlInitializer, nsnull)
public: //for methods who access nsTextControlFrame directly
void FireOnInput(PRBool aTrusted);
void SetValueChanged(PRBool aValueChanged);
@ -286,23 +291,27 @@ protected:
class EditorInitializer : public nsRunnable {
public:
EditorInitializer(nsTextControlFrame* aFrame) :
mWeakFrame(aFrame),
mFrame(aFrame) {}
NS_IMETHOD Run() {
if (mWeakFrame) {
if (mFrame) {
nsCOMPtr<nsIPresShell> shell =
mWeakFrame.GetFrame()->PresContext()->GetPresShell();
mFrame->PresContext()->GetPresShell();
PRBool observes = shell->ObservesNativeAnonMutationsForPrint();
shell->ObserveNativeAnonMutationsForPrint(PR_TRUE);
mFrame->EnsureEditorInitialized();
shell->ObserveNativeAnonMutationsForPrint(observes);
mFrame->FinishedInitializer();
}
return NS_OK;
}
// avoids use of nsWeakFrame
void Revoke() {
mFrame = nsnull;
}
private:
nsWeakFrame mWeakFrame;
nsTextControlFrame* mFrame;
};
@ -388,6 +397,10 @@ private:
*/
nsresult GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement);
void FinishedInitializer() {
Properties().Delete(TextControlInitializer());
}
private:
// these packed bools could instead use the high order bits on mState, saving 4 bytes
PRPackedBool mUseEditor;