diff --git a/content/html/content/src/nsTextEditorState.cpp b/content/html/content/src/nsTextEditorState.cpp
index ddb7968d6ba..75440592411 100644
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -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 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 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 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 (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
diff --git a/content/html/content/src/nsTextEditorState.h b/content/html/content/src/nsTextEditorState.h
index ec707dae03e..b0cf011103c 100644
--- a/content/html/content/src/nsTextEditorState.h
+++ b/content/html/content/src/nsTextEditorState.h
@@ -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 mSelCon;
nsAutoPtr mSelState;
+ RestoreSelectionState* mRestoringSelection;
nsCOMPtr mEditor;
nsCOMPtr mRootNode;
nsCOMPtr mPlaceholderDiv;
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
index e6ad1347f49..e777abdc3f0 100644
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -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 txtCtrl = do_QueryInterface(GetContent());
@@ -445,10 +451,17 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray& 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;
diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h
index f6e87c6f20f..638c6981204 100644
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -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 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;