Bug 802985, PreDestroy editor, r=ehsan
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 20 Oct 2012 21:48:34 +0300
changeset 119519 92e4438ecf5e233da0243c1082e7af1758ce0672
parent 119518 5d03feda23009d5a79a1ed880a6ff20af57dbf2b
child 119520 034634c4125ae8bfd14f9aa16b5df813c16a136b
push id273
push userlsblakk@mozilla.com
push dateThu, 14 Feb 2013 23:19:38 +0000
treeherdermozilla-release@c5e807a3f8b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs802985
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 802985, PreDestroy editor, r=ehsan
content/html/content/src/nsTextEditorState.cpp
editor/libeditor/text/nsTextEditRules.cpp
layout/forms/nsTextControlFrame.cpp
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1117,16 +1117,36 @@ nsTextEditorState::BindToFrame(nsTextCon
     if (!nsContentUtils::AddScriptRunner(
           new PrepareEditorEvent(*this, content, currentValue)))
       return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
+struct PreDestroyer
+{
+  void Init(nsIEditor* aEditor)
+  {
+    mNewEditor = aEditor;
+  }
+  ~PreDestroyer()
+  {
+    if (mNewEditor) {
+      mNewEditor->PreDestroy(true);
+    }
+  }
+  void Swap(nsCOMPtr<nsIEditor>& aEditor)
+  {
+    return mNewEditor.swap(aEditor);
+  }
+private:
+  nsCOMPtr<nsIEditor> mNewEditor;
+};
+
 nsresult
 nsTextEditorState::PrepareEditor(const nsAString *aValue)
 {
   if (!mBoundFrame) {
     // Cannot create an editor without a bound frame.
     // Don't return a failure code, because js callers can't handle that.
     return NS_OK;
   }
@@ -1163,22 +1183,24 @@ nsTextEditorState::PrepareEditor(const n
 
   // Spell check is diabled at creation time. It is enabled once
   // the editor comes into focus.
   editorFlags |= nsIPlaintextEditor::eEditorSkipSpellCheck;
 
   bool shouldInitializeEditor = false;
   nsCOMPtr<nsIEditor> newEditor; // the editor that we might create
   nsresult rv = NS_OK;
+  PreDestroyer preDestroyer;
   if (!mEditor) {
     shouldInitializeEditor = true;
 
     // Create an editor
     newEditor = do_CreateInstance(kTextEditorCID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
+    preDestroyer.Init(newEditor);
 
     // Make sure we clear out the non-breaking space before we initialize the editor
     rv = mBoundFrame->UpdateValueDisplay(false, true);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     if (aValue || !mEditorInitialized) {
       // Set the correct value in the root node
       rv = mBoundFrame->UpdateValueDisplay(true, !mEditorInitialized, aValue);
@@ -1297,17 +1319,17 @@ nsTextEditorState::PrepareEditor(const n
   if (aValue) {
     defaultValue = *aValue;
   } else {
     GetValue(defaultValue, true);
   }
 
   if (shouldInitializeEditor) {
     // Hold on to the newly created editor
-    mEditor = newEditor;
+    preDestroyer.Swap(mEditor);
   }
 
   // If we have a default value, insert it under the div we created
   // above, but be sure to use the editor so that '*' characters get
   // displayed for password fields, etc. SetValue() will call the
   // editor for us.
 
   if (!defaultValue.IsEmpty()) {
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -99,17 +99,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTextE
 NS_IMETHODIMP
 nsTextEditRules::Init(nsPlaintextEditor *aEditor)
 {
   if (!aEditor) { return NS_ERROR_NULL_POINTER; }
 
   mEditor = aEditor;  // we hold a non-refcounted reference back to our editor
   nsCOMPtr<nsISelection> selection;
   mEditor->GetSelection(getter_AddRefs(selection));
-  NS_ASSERTION(selection, "editor cannot get selection");
+  NS_WARN_IF_FALSE(selection, "editor cannot get selection");
 
   // Put in a magic br if needed. This method handles null selection,
   // which should never happen anyway
   nsresult res = CreateBogusNodeIfNeeded(selection);
   NS_ENSURE_SUCCESS(res, res);
 
   // If the selection hasn't been set up yet, set it up collapsed to the end of
   // our editable content.
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -291,60 +291,63 @@ nsTextControlFrame::EnsureEditorInitiali
   // Flush out content on our document.  Have to do this, because script
   // blockers don't prevent the sink flushing out content and notifying in the
   // process, which can destroy frames.
   doc->FlushPendingNotifications(Flush_ContentAndNotify);
   NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE);
 
   // Make sure that editor init doesn't do things that would kill us off
   // (especially off the script blockers it'll create for its DOM mutations).
-  nsAutoScriptBlocker scriptBlocker;
+  {
+    nsAutoScriptBlocker scriptBlocker;
 
-  // Time to mess with our security context... See comments in GetValue()
-  // for why this is needed.
-  nsCxPusher pusher;
-  pusher.PushNull();
+    // Time to mess with our security context... See comments in GetValue()
+    // for why this is needed.
+    nsCxPusher pusher;
+    pusher.PushNull();
 
-  // Make sure that we try to focus the content even if the method fails
-  class EnsureSetFocus {
-  public:
-    explicit EnsureSetFocus(nsTextControlFrame* aFrame)
-      : mFrame(aFrame) {}
-    ~EnsureSetFocus() {
-      if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
-        mFrame->SetFocus(true, false);
-    }
-  private:
-    nsTextControlFrame *mFrame;
-  };
-  EnsureSetFocus makeSureSetFocusHappens(this);
+    // Make sure that we try to focus the content even if the method fails
+    class EnsureSetFocus {
+    public:
+      explicit EnsureSetFocus(nsTextControlFrame* aFrame)
+        : mFrame(aFrame) {}
+      ~EnsureSetFocus() {
+        if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
+          mFrame->SetFocus(true, false);
+      }
+    private:
+      nsTextControlFrame *mFrame;
+    };
+    EnsureSetFocus makeSureSetFocusHappens(this);
 
 #ifdef DEBUG
-  // Make sure we are not being called again until we're finished.
-  // If reentrancy happens, just pretend that we don't have an editor.
-  const EditorInitializerEntryTracker tracker(*this);
-  NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
-               "EnsureEditorInitialized has been called while a previous call was in progress");
+    // Make sure we are not being called again until we're finished.
+    // If reentrancy happens, just pretend that we don't have an editor.
+    const EditorInitializerEntryTracker tracker(*this);
+    NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
+                 "EnsureEditorInitialized has been called while a previous call was in progress");
 #endif
 
-  // Create an editor for the frame, if one doesn't already exist
-  nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
-  NS_ASSERTION(txtCtrl, "Content not a text control element");
-  nsresult rv = txtCtrl->CreateEditor();
-  NS_ENSURE_SUCCESS(rv, rv);
+    // Create an editor for the frame, if one doesn't already exist
+    nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
+    NS_ASSERTION(txtCtrl, "Content not a text control element");
+    nsresult rv = txtCtrl->CreateEditor();
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_STATE(weakFrame.IsAlive());
 
-  // Turn on mUseEditor so that subsequent calls will use the
-  // editor.
-  mUseEditor = true;
+    // Turn on mUseEditor so that subsequent calls will use the
+    // editor.
+    mUseEditor = true;
 
-  // Set the selection to the beginning of the text field.
-  if (weakFrame.IsAlive()) {
-    SetSelectionEndPoints(0, 0);
+    // Set the selection to the beginning of the text field.
+    if (weakFrame.IsAlive()) {
+      SetSelectionEndPoints(0, 0);
+    }
   }
-
+  NS_ENSURE_STATE(weakFrame.IsAlive());
   return NS_OK;
 }
 
 nsresult
 nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   NS_ASSERTION(mContent, "We should have a content!");
 
@@ -1084,18 +1087,20 @@ nsTextControlFrame::GetSelectionRange(in
       NS_NOTREACHED("Invalid nsDirection enum value");
     }
   }
 
   if (!aSelectionStart || !aSelectionEnd) {
     return NS_OK;
   }
 
-  nsContentUtils::GetSelectionInTextControl(typedSel,
-    GetRootNodeAndInitializeEditor(), *aSelectionStart, *aSelectionEnd);
+  mozilla::dom::Element* root = GetRootNodeAndInitializeEditor();
+  NS_ENSURE_STATE(root);
+  nsContentUtils::GetSelectionInTextControl(typedSel, root,
+                                            *aSelectionStart, *aSelectionEnd);
 
   return NS_OK;
 }
 
 /////END INTERFACE IMPLEMENTATIONS
 
 ////NSIFRAME
 NS_IMETHODIMP