Bug 558970 nsEditorEventListener should store its owner as nsEditor rather than nsIEditor r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 19 Apr 2010 21:20:42 +0900
changeset 40987 d7085006cb18f536a635a1b36e7faee96420ed58
parent 40986 a0b7fc3ed2ef1a9b455db3f3c379d0b4d398b95a
child 40988 1908834320d8122a7bb7f32be15e3d5b9dc9fd0c
push id12866
push usermasayuki@d-toybox.com
push dateMon, 19 Apr 2010 12:21:44 +0000
treeherdermozilla-central@d7085006cb18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs558970
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 558970 nsEditorEventListener should store its owner as nsEditor rather than nsIEditor r=smaug
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/base/nsEditorEventListener.h
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/nsHTMLEditorEventListener.cpp
editor/libeditor/html/nsHTMLEditorEventListener.h
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -39,38 +39,30 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "pratom.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMNSHTMLElement.h"
-#include "nsIDOMEventTarget.h"
 #include "nsPIDOMEventTarget.h"
-#include "nsIEventListenerManager.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 
 #include "nsIDOMText.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMNamedNodeMap.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMRange.h"
-#include "nsIDOMEventListener.h"
-#include "nsIDOMEventGroup.h"
-#include "nsIDOMMouseListener.h"
-#include "nsIDOMFocusListener.h"
-#include "nsIDOMTextListener.h"
-#include "nsIDOMCompositionListener.h"
 #include "nsIDOMHTMLBRElement.h"
 #include "nsIDocument.h"
 #include "nsITransactionManager.h"
 #include "nsIAbsorbingTransaction.h"
 #include "nsIPresShell.h"
 #include "nsIViewManager.h"
 #include "nsISelection.h"
 #include "nsISelectionPrivate.h"
@@ -313,141 +305,38 @@ nsEditor::PostCreate()
   return NS_OK;
 }
 
 nsresult
 nsEditor::CreateEventListeners()
 {
   NS_ENSURE_TRUE(!mEventListener, NS_ERROR_ALREADY_INITIALIZED);
   mEventListener = do_QueryInterface(
-    static_cast<nsIDOMKeyListener*>(new nsEditorEventListener(this)));
+    static_cast<nsIDOMKeyListener*>(new nsEditorEventListener()));
   NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
   return NS_OK;
 }
 
 nsresult
 nsEditor::InstallEventListeners()
 {
   NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
                  NS_ERROR_NOT_INITIALIZED);
-
-  nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
-
-  if (!piTarget) {
-    RemoveEventListeners();
-    return NS_ERROR_FAILURE;
-  }
-
-  nsresult rv = NS_OK;
-
-  // register the event listeners with the listener manager
-  nsCOMPtr<nsIDOMEventGroup> sysGroup;
-  piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
-  nsIEventListenerManager* elmP = piTarget->GetListenerManager(PR_TRUE);
-
-  if (sysGroup && elmP)
-  {
-    rv = elmP->AddEventListenerByType(mEventListener,
-                                      NS_LITERAL_STRING("keypress"),
-                                      NS_EVENT_FLAG_BUBBLE |
-                                      NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
-                                      sysGroup);
-    NS_ASSERTION(NS_SUCCEEDED(rv),
-                 "failed to register key listener in system group");
-  }
-
-  rv |= piTarget->AddEventListenerByIID(mEventListener,
-                                        NS_GET_IID(nsIDOMMouseListener));
-
-  if (elmP) {
-    // Focus event doesn't bubble so adding the listener to capturing phase.
-    // Make sure this works after bug 235441 gets fixed.
-    rv |= elmP->AddEventListenerByIID(mEventListener,
-                                      NS_GET_IID(nsIDOMFocusListener),
-                                      NS_EVENT_FLAG_CAPTURE);
-  }
-
-  rv |= piTarget->AddEventListenerByIID(mEventListener,
-                                        NS_GET_IID(nsIDOMTextListener));
-
-  rv |= piTarget->AddEventListenerByIID(mEventListener,
-                                        NS_GET_IID(nsIDOMCompositionListener));
-
-  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget));
-  if (target) {
-    // See bug 455215, we cannot use the standard dragstart event yet
-    rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
-                                       NS_EVENT_FLAG_BUBBLE, sysGroup);
-    rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragenter"),
-                                       NS_EVENT_FLAG_BUBBLE, sysGroup);
-    rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragover"),
-                                       NS_EVENT_FLAG_BUBBLE, sysGroup);
-    rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragleave"),
-                                       NS_EVENT_FLAG_BUBBLE, sysGroup);
-    rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("drop"),
-                                       NS_EVENT_FLAG_BUBBLE, sysGroup);
-  }
-
-  if (NS_FAILED(rv))
-  {
-    NS_ERROR("failed to register some event listeners");
-
-    RemoveEventListeners();
-  }
-
-  return rv;
+  nsEditorEventListener* listener =
+    reinterpret_cast<nsEditorEventListener*>(mEventListener.get());
+  return listener->Connect(this);
 }
 
 void
 nsEditor::RemoveEventListeners()
 {
-  if (!mDocWeak || !mEventListener)
-  {
+  if (!mDocWeak || !mEventListener) {
     return;
   }
-
-  nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
-
-  if (piTarget)
-  {
-    // unregister the event listeners with the DOM event target
-    nsCOMPtr<nsIEventListenerManager> elmP =
-      piTarget->GetListenerManager(PR_TRUE);
-    nsCOMPtr<nsIDOMEventGroup> sysGroup;
-    piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
-    if (sysGroup && elmP)
-    {
-      elmP->RemoveEventListenerByType(mEventListener,
-                                      NS_LITERAL_STRING("keypress"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-      elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-      elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragenter"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-      elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragover"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-      elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragleave"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-      elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("drop"),
-                                      NS_EVENT_FLAG_BUBBLE, sysGroup);
-    }
-
-    piTarget->RemoveEventListenerByIID(mEventListener,
-                                       NS_GET_IID(nsIDOMMouseListener));
-
-    elmP->RemoveEventListenerByIID(mEventListener,
-                                   NS_GET_IID(nsIDOMFocusListener),
-                                   NS_EVENT_FLAG_CAPTURE);
-
-    piTarget->RemoveEventListenerByIID(mEventListener,
-                                       NS_GET_IID(nsIDOMTextListener));
-
-    piTarget->RemoveEventListenerByIID(mEventListener,
-                                       NS_GET_IID(nsIDOMCompositionListener));
-  }
+  reinterpret_cast<nsEditorEventListener*>(mEventListener.get())->Disconnect();
 }
 
 PRBool
 nsEditor::GetDesiredSpellCheckState()
 {
   // Check user override on this element
   if (mSpellcheckCheckboxState != eTriUnset) {
     return (mSpellcheckCheckboxState == eTriTrue);
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -339,17 +339,17 @@ protected:
                            nsCOMPtr<nsIDOMNode> *aResultNode,
                            PRBool       bNoBlockCrossing = PR_FALSE);
 
   // Get nsIWidget interface
   nsresult GetWidget(nsIWidget **aWidget);
 
 
   // install the event listeners for the editor 
-  nsresult InstallEventListeners();
+  virtual nsresult InstallEventListeners();
 
   virtual nsresult CreateEventListeners();
 
   // unregister and release our event listeners
   virtual void RemoveEventListeners();
 
   /**
    * Return true if spellchecking should be enabled for this editor.
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -40,29 +40,32 @@
 #include "nsEditorEventListener.h"
 #include "nsEditor.h"
 #include "nsIPlaintextEditor.h"
 
 #include "nsIDOMDOMStringList.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMDocument.h"
+#include "nsPIDOMEventTarget.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsIPrivateTextEvent.h"
 #include "nsIEditorMailSupport.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsILookAndFeel.h"
 #include "nsFocusManager.h"
+#include "nsIEventListenerManager.h"
+#include "nsIDOMEventGroup.h"
 
 // Drag & Drop, Clipboard
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsIDragService.h"
 #include "nsIDragSession.h"
 #include "nsIContent.h"
 #include "nsISupportsPrimitives.h"
@@ -71,34 +74,183 @@
 #include "nsIDOMEventTarget.h"
 #include "nsIEventStateManager.h"
 #include "nsISelectionPrivate.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIFocusManager.h"
 #include "nsIDOMWindow.h"
 #include "nsContentUtils.h"
 
-nsEditorEventListener::nsEditorEventListener(nsEditor* aEditor) :
-  mEditor(aEditor), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
+nsEditorEventListener::nsEditorEventListener() :
+  mEditor(nsnull), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
   mInTransaction(PR_FALSE)
 {
 }
 
 nsEditorEventListener::~nsEditorEventListener() 
 {
+  if (mEditor) {
+    NS_WARNING("We're not uninstalled");
+    Disconnect();
+  }
+}
+
+nsresult
+nsEditorEventListener::Connect(nsEditor* aEditor)
+{
+  NS_ENSURE_ARG(aEditor);
+  NS_ENSURE_TRUE(!mEditor, NS_ERROR_NOT_AVAILABLE);
+
+  mEditor = aEditor;
+
+  nsresult rv = InstallToEditor();
+  if (NS_FAILED(rv)) {
+    Disconnect();
+  }
+  return rv;
+}
+
+nsresult
+nsEditorEventListener::InstallToEditor()
+{
+  NS_PRECONDITION(mEditor, "The caller must set mEditor");
+
+  nsCOMPtr<nsPIDOMEventTarget> piTarget = mEditor->GetPIDOMEventTarget();
+  NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
+
+  nsresult rv;
+
+  // register the event listeners with the listener manager
+  nsCOMPtr<nsIDOMEventGroup> sysGroup;
+  piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
+  NS_ENSURE_STATE(sysGroup);
+  nsIEventListenerManager* elmP = piTarget->GetListenerManager(PR_TRUE);
+  NS_ENSURE_STATE(elmP);
+
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("keypress"),
+                                    NS_EVENT_FLAG_BUBBLE |
+                                    NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
+                                    sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+  // See bug 455215, we cannot use the standard dragstart event yet
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("draggesture"),
+                                    NS_EVENT_FLAG_BUBBLE, sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("dragenter"),
+                                    NS_EVENT_FLAG_BUBBLE, sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("dragover"),
+                                    NS_EVENT_FLAG_BUBBLE, sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("dragleave"),
+                                    NS_EVENT_FLAG_BUBBLE, sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                    NS_LITERAL_STRING("drop"),
+                                    NS_EVENT_FLAG_BUBBLE, sysGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = piTarget->AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
+                                       NS_GET_IID(nsIDOMMouseListener));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Focus event doesn't bubble so adding the listener to capturing phase.
+  // Make sure this works after bug 235441 gets fixed.
+  rv = elmP->AddEventListenerByIID(static_cast<nsIDOMFocusListener*>(this),
+                                   NS_GET_IID(nsIDOMFocusListener),
+                                   NS_EVENT_FLAG_CAPTURE);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = piTarget->AddEventListenerByIID(static_cast<nsIDOMTextListener*>(this),
+                                       NS_GET_IID(nsIDOMTextListener));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = piTarget->AddEventListenerByIID(
+    static_cast<nsIDOMCompositionListener*>(this),
+    NS_GET_IID(nsIDOMCompositionListener));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+void
+nsEditorEventListener::Disconnect()
+{
+  if (!mEditor) {
+    return;
+  }
+  UninstallFromEditor();
+  mEditor = nsnull;
+}
+
+void
+nsEditorEventListener::UninstallFromEditor()
+{
+  nsCOMPtr<nsPIDOMEventTarget> piTarget = mEditor->GetPIDOMEventTarget();
+  if (!piTarget) {
+    return;
+  }
+
+  nsCOMPtr<nsIEventListenerManager> elmP =
+    piTarget->GetListenerManager(PR_TRUE);
+  if (!elmP) {
+    return;
+  }
+  nsCOMPtr<nsIDOMEventGroup> sysGroup;
+  piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
+  if (!sysGroup) {
+    return;
+  }
+
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("keypress"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("draggesture"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("dragenter"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("dragover"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("dragleave"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+  elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
+                                  NS_LITERAL_STRING("drop"),
+                                  NS_EVENT_FLAG_BUBBLE, sysGroup);
+
+  piTarget->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
+                                     NS_GET_IID(nsIDOMMouseListener));
+
+  elmP->RemoveEventListenerByIID(static_cast<nsIDOMFocusListener*>(this),
+                                 NS_GET_IID(nsIDOMFocusListener),
+                                 NS_EVENT_FLAG_CAPTURE);
+
+  piTarget->RemoveEventListenerByIID(static_cast<nsIDOMTextListener*>(this),
+                                     NS_GET_IID(nsIDOMTextListener));
+
+  piTarget->RemoveEventListenerByIID(
+    static_cast<nsIDOMCompositionListener*>(this),
+    NS_GET_IID(nsIDOMCompositionListener));
 }
 
 already_AddRefed<nsIPresShell>
 nsEditorEventListener::GetPresShell()
 {
-  NS_ENSURE_TRUE(mEditor, nsnull);
-  // mEditor is nsEditor or its inherited class.
-  // This is guaranteed by constructor.
+  NS_PRECONDITION(mEditor,
+    "The caller must check whether this is connected to an editor");
   nsCOMPtr<nsIPresShell> ps;
-  static_cast<nsEditor*>(mEditor)->GetPresShell(getter_AddRefs(ps));
+  mEditor->GetPresShell(getter_AddRefs(ps));
   return ps.forget();
 }
 
 /**
  *  nsISupports implementation
  */
 
 NS_IMPL_ADDREF(nsEditorEventListener)
@@ -116,16 +268,18 @@ NS_INTERFACE_MAP_END
 
 /**
  *  nsIDOMEventListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
   if (dragEvent) {
     nsAutoString eventType;
     aEvent->GetType(eventType);
     if (eventType.EqualsLiteral("draggesture"))
       return DragGesture(dragEvent);
     if (eventType.EqualsLiteral("dragenter"))
       return DragEnter(dragEvent);
@@ -141,28 +295,34 @@ nsEditorEventListener::HandleEvent(nsIDO
 
 /**
  * nsIDOMKeyListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::KeyDown(nsIDOMEvent* aKeyEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::KeyUp(nsIDOMEvent* aKeyEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   // DOM event handling happens in two passes, the client pass and the system
   // pass.  We do all of our processing in the system pass, to allow client
   // handlers the opportunity to cancel events and prevent typing in the editor.
   // If the client pass cancelled the event, defaultPrevented will be true
   // below.
 
   nsCOMPtr<nsIDOMNSUIEvent> nsUIEvent = do_QueryInterface(aKeyEvent);
   if(nsUIEvent) 
@@ -179,29 +339,29 @@ nsEditorEventListener::KeyPress(nsIDOMEv
     //non-key event passed to keypress.  bad things.
     return NS_OK;
   }
 
   PRUint32 keyCode;
   keyEvent->GetKeyCode(&keyCode);
 
   // if we are readonly or disabled, then do nothing.
-  nsEditor* editor = static_cast<nsEditor*>(mEditor);
-  if (editor->IsReadonly() || editor->IsDisabled())
+  if (mEditor->IsReadonly() || mEditor->IsDisabled())
   {
     // consume backspace for disabled and readonly textfields, to prevent
     // back in history, which could be confusing to users
     if (keyCode == nsIDOMKeyEvent::DOM_VK_BACK_SPACE)
       aKeyEvent->PreventDefault();
 
     return NS_OK;
   }
 
-  nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
-  if (!textEditor) return NS_ERROR_NO_INTERFACE;
+  nsCOMPtr<nsIPlaintextEditor> textEditor =
+    do_QueryInterface(static_cast<nsIEditor*>(mEditor));
+  NS_ASSERTION(textEditor, "nsEditor must have nsIPlaintextEditor");
 
   // if there is no charCode, then it's a key that doesn't map to a character,
   // so look for special keys using keyCode.
   if (0 != keyCode)
   {
     PRBool isAnyModifierKeyButShift;
     nsresult rv;
     rv = keyEvent->GetAltKey(&isAnyModifierKeyButShift);
@@ -249,35 +409,35 @@ nsEditorEventListener::KeyPress(nsIDOMEv
         if (isAnyModifierKeyButShift || isShiftModifierKey)
            return NS_OK;
         mEditor->DeleteSelection(nsIEditor::eNext);
         aKeyEvent->PreventDefault(); // consumed
         return NS_OK; 
         break;
  
       case nsIDOMKeyEvent::DOM_VK_TAB:
-        if (editor->IsSingleLineEditor() || editor->IsPasswordEditor() ||
-            editor->IsFormWidget() || editor->IsInteractionAllowed()) {
+        if (mEditor->IsSingleLineEditor() || mEditor->IsPasswordEditor() ||
+            mEditor->IsFormWidget() || mEditor->IsInteractionAllowed()) {
           return NS_OK; // let it be used for focus switching
         }
 
         if (isAnyModifierKeyButShift)
           return NS_OK;
 
         // else we insert the tab straight through
         textEditor->HandleKeyPress(keyEvent);
         // let HandleKeyPress consume the event
         return NS_OK; 
 
       case nsIDOMKeyEvent::DOM_VK_RETURN:
       case nsIDOMKeyEvent::DOM_VK_ENTER:
         if (isAnyModifierKeyButShift)
           return NS_OK;
 
-        if (!editor->IsSingleLineEditor())
+        if (!mEditor->IsSingleLineEditor())
         {
           textEditor->HandleKeyPress(keyEvent);
           aKeyEvent->PreventDefault(); // consumed
         }
         return NS_OK;
     }
   }
 
@@ -287,16 +447,18 @@ nsEditorEventListener::KeyPress(nsIDOMEv
 
 /**
  * nsIDOMMouseListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
   nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aMouseEvent);
   PRBool isTrusted = PR_FALSE;
   if (!mouseEvent || !nsevent ||
       NS_FAILED(nsevent->GetIsTrusted(&isTrusted)) || !isTrusted) {
     // Non-ui or non-trusted event passed in. Bad things.
     return NS_OK;
   }
@@ -309,24 +471,19 @@ nsEditorEventListener::MouseClick(nsIDOM
   PRBool preventDefault;
   rv = nsuiEvent->GetPreventDefault(&preventDefault);
   if (NS_FAILED(rv) || preventDefault)
   {
     // We're done if 'preventdefault' is true (see for example bug 70698).
     return rv;
   }
 
-  nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
-  if (!editor) { return NS_OK; }
-
   // If we got a mouse down inside the editing area, we should force the 
   // IME to commit before we change the cursor position
-  nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(mEditor);
-  if (imeEditor)
-    imeEditor->ForceCompositionEnd();
+  mEditor->ForceCompositionEnd();
 
   PRUint16 button = (PRUint16)-1;
   mouseEvent->GetButton(&button);
   // middle-mouse click (paste);
   if (button == 1)
   {
     nsCOMPtr<nsIPrefBranch> prefBranch =
       do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
@@ -340,40 +497,40 @@ nsEditorEventListener::MouseClick(nsIDOM
         nsCOMPtr<nsIDOMNode> parent;
         if (NS_FAILED(nsuiEvent->GetRangeParent(getter_AddRefs(parent))))
           return NS_ERROR_NULL_POINTER;
         PRInt32 offset = 0;
         if (NS_FAILED(nsuiEvent->GetRangeOffset(&offset)))
           return NS_ERROR_NULL_POINTER;
 
         nsCOMPtr<nsISelection> selection;
-        if (NS_SUCCEEDED(editor->GetSelection(getter_AddRefs(selection))))
+        if (NS_SUCCEEDED(mEditor->GetSelection(getter_AddRefs(selection))))
           (void)selection->Collapse(parent, offset);
 
         // If the ctrl key is pressed, we'll do paste as quotation.
         // Would've used the alt key, but the kde wmgr treats alt-middle specially. 
         PRBool ctrlKey = PR_FALSE;
         mouseEvent->GetCtrlKey(&ctrlKey);
 
         nsCOMPtr<nsIEditorMailSupport> mailEditor;
         if (ctrlKey)
-          mailEditor = do_QueryInterface(mEditor);
+          mailEditor = do_QueryInterface(static_cast<nsIEditor*>(mEditor));
 
         PRInt32 clipboard;
 
 #if defined(XP_OS2) || defined(XP_WIN32)
         clipboard = nsIClipboard::kGlobalClipboard;
 #else
         clipboard = nsIClipboard::kSelectionClipboard;
 #endif
 
         if (mailEditor)
           mailEditor->PasteAsQuotation(clipboard);
         else
-          editor->Paste(clipboard);
+          mEditor->Paste(clipboard);
 
         // Prevent the event from propagating up to be possibly handled
         // again by the containing window:
         mouseEvent->StopPropagation();
         mouseEvent->PreventDefault();
 
         // We processed the event, whether drop/paste succeeded or not
         return NS_OK;
@@ -381,85 +538,89 @@ nsEditorEventListener::MouseClick(nsIDOM
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
 {
-  nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(mEditor);
-  if (!imeEditor)
-    return NS_OK;
-  imeEditor->ForceCompositionEnd();
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  mEditor->ForceCompositionEnd();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseOver(nsIDOMEvent* aMouseEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::MouseOut(nsIDOMEvent* aMouseEvent)
 {
+  // WARNING: If you change this method, you comment out next line.
+  // NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   return NS_OK;
 }
 
 /**
  * nsIDOMTextListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIPrivateTextEvent> textEvent = do_QueryInterface(aTextEvent);
   if (!textEvent) {
      //non-ui event passed in.  bad things.
      return NS_OK;
   }
 
   nsAutoString                      composedText;
   nsCOMPtr<nsIPrivateTextRangeList> textRangeList;
 
   textEvent->GetText(composedText);
   textRangeList = textEvent->GetInputRange();
 
-  nsEditor* editor = static_cast<nsEditor*>(mEditor);
   // if we are readonly or disabled, then do nothing.
-  if (editor->IsReadonly() || editor->IsDisabled()) {
+  if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return NS_OK;
   }
 
-  return editor->SetCompositionString(composedText, textRangeList);
+  return mEditor->SetCompositionString(composedText, textRangeList);
 }
 
 /**
  * Drag event implementation
  */
 
 nsresult
 nsEditorEventListener::DragGesture(nsIDOMDragEvent* aDragEvent)
 {
-  if ( !mEditor )
-    return NS_ERROR_NULL_POINTER;
-
   // ...figure out if a drag should be started...
   PRBool canDrag;
   nsresult rv = mEditor->CanDrag(aDragEvent, &canDrag);
   if ( NS_SUCCEEDED(rv) && canDrag )
     rv = mEditor->DoDrag(aDragEvent);
 
   return rv;
 }
@@ -569,19 +730,16 @@ nsEditorEventListener::Drop(nsIDOMDragEv
 
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     if (presShell)
     {
       presShell->RestoreCaret();
     }
   }
 
-  if (!mEditor)
-    return NS_ERROR_FAILURE;
-
   nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aMouseEvent);
   if (nsuiEvent) {
     PRBool defaultPrevented;
     nsuiEvent->GetPreventDefault(&defaultPrevented);
     if (defaultPrevented)
       return NS_OK;
 
     nsCOMPtr<nsIDOMNode> parent;
@@ -593,18 +751,17 @@ nsEditorEventListener::Drop(nsIDOMDragEv
     if (!dropParent->IsEditable())
       return NS_OK;
   }
 
   PRBool canDrop = CanDrop(aMouseEvent);
   if (!canDrop)
   {
     // was it because we're read-only?
-    nsEditor* editor = static_cast<nsEditor*>(mEditor);
-    if (editor->IsReadonly() || editor->IsDisabled())
+    if (mEditor->IsReadonly() || mEditor->IsDisabled())
     {
       // it was decided to "eat" the event as this is the "least surprise"
       // since someone else handling it might be unintentional and the 
       // user could probably re-drag to be not over the disabled/readonly 
       // editfields if that is what is desired.
       return aMouseEvent->StopPropagation();
     }
     return NS_OK;
@@ -616,18 +773,17 @@ nsEditorEventListener::Drop(nsIDOMDragEv
   // ScrollSelectionIntoView.
   return mEditor->InsertFromDrop(aMouseEvent);
 }
 
 PRBool
 nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
 {
   // if the target doc is read-only, we can't drop
-  nsEditor* editor = static_cast<nsEditor*>(mEditor);
-  if (editor->IsReadonly() || editor->IsDisabled()) {
+  if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return PR_FALSE;
   }
 
   nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
   aEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
   if (!dataTransfer)
     return PR_FALSE;
 
@@ -637,17 +793,17 @@ nsEditorEventListener::CanDrop(nsIDOMDra
     return PR_FALSE;
 
   // Plaintext editors only support dropping text. Otherwise, HTML and files
   // can be dropped as well.
   PRBool typeSupported;
   types->Contains(NS_LITERAL_STRING(kTextMime), &typeSupported);
   if (!typeSupported) {
     types->Contains(NS_LITERAL_STRING(kMozTextInternal), &typeSupported);
-    if (!typeSupported && !editor->IsPlaintextEditor()) {
+    if (!typeSupported && !mEditor->IsPlaintextEditor()) {
       types->Contains(NS_LITERAL_STRING(kHTMLMime), &typeSupported);
       if (!typeSupported) {
         types->Contains(NS_LITERAL_STRING(kFileMime), &typeSupported);
       }
     }
   }
 
   if (!typeSupported)
@@ -725,32 +881,35 @@ nsEditorEventListener::CanDrop(nsIDOMDra
 
 /**
  * nsIDOMCompositionListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
 {
-  return static_cast<nsEditor*>(mEditor)->BeginComposition();
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  return mEditor->BeginComposition();
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
 {
-  return static_cast<nsEditor*>(mEditor)->EndComposition();
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  return mEditor->EndComposition();
 }
 
 /**
  * nsIDOMFocusListener implementation
  */
 
 static already_AddRefed<nsIContent>
 FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
 {
+  NS_PRECONDITION(aEditor, "aEditor must not be null");
   nsIDocument *document = aContent->GetCurrentDoc();
   if (!document) {
     return nsnull;
   }
 
   nsIContent *root;
   if (document->HasFlag(NODE_IS_EDITABLE)) {
     NS_IF_ADDREF(root = document->GetRootContent());
@@ -785,151 +944,143 @@ FindSelectionRoot(nsEditor *aEditor, nsI
   NS_IF_ADDREF(content);
 
   return content;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_ARG(aEvent);
 
   nsCOMPtr<nsIDOMEventTarget> target;
   aEvent->GetTarget(getter_AddRefs(target));
 
   // turn on selection and caret
-  if (mEditor)
-  {
-    nsEditor* editor = static_cast<nsEditor*>(mEditor);
-    if (!editor->IsDisabled())
-    { // only enable caret and selection if the editor is not disabled
-      nsCOMPtr<nsIContent> content = do_QueryInterface(target);
+  if (mEditor->IsDisabled()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIContent> content = do_QueryInterface(target);
+
+  PRBool targetIsEditableDoc = PR_FALSE;
+  nsCOMPtr<nsIContent> editableRoot;
+  if (content) {
+    editableRoot = FindSelectionRoot(mEditor, content);
+
+    // make sure that the element is really focused in case an earlier
+    // listener in the chain changed the focus.
+    if (editableRoot) {
+      nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+      NS_ENSURE_TRUE(fm, NS_OK);
 
-      PRBool targetIsEditableDoc = PR_FALSE;
-      nsCOMPtr<nsIContent> editableRoot;
-      if (content) {
-        editableRoot = FindSelectionRoot(editor, content);
+      nsCOMPtr<nsIDOMElement> element;
+      fm->GetFocusedElement(getter_AddRefs(element));
+      if (!SameCOMIdentity(element, target))
+        return NS_OK;
+    }
+  }
+  else {
+    nsCOMPtr<nsIDocument> document = do_QueryInterface(target);
+    targetIsEditableDoc = document && document->HasFlag(NODE_IS_EDITABLE);
+  }
 
-        // make sure that the element is really focused in case an earlier
-        // listener in the chain changed the focus.
-        if (editableRoot) {
-          nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-          NS_ENSURE_TRUE(fm, NS_OK);
+  nsCOMPtr<nsISelectionController> selCon;
+  mEditor->GetSelectionController(getter_AddRefs(selCon));
+  if (selCon && (targetIsEditableDoc || editableRoot))
+  {
+    nsCOMPtr<nsISelection> selection;
+    selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+                         getter_AddRefs(selection));
 
-          nsCOMPtr<nsIDOMElement> element;
-          fm->GetFocusedElement(getter_AddRefs(element));
-          if (!SameCOMIdentity(element, target))
-            return NS_OK;
+    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+    if (presShell) {
+      nsRefPtr<nsCaret> caret = presShell->GetCaret();
+      if (caret) {
+        caret->SetIgnoreUserModify(PR_FALSE);
+        if (selection) {
+          caret->SetCaretDOMSelection(selection);
         }
       }
-      else {
-        nsCOMPtr<nsIDocument> document = do_QueryInterface(target);
-        targetIsEditableDoc = document && document->HasFlag(NODE_IS_EDITABLE);
-      }
+    }
 
-      nsCOMPtr<nsISelectionController> selCon;
-      mEditor->GetSelectionController(getter_AddRefs(selCon));
-      if (selCon && (targetIsEditableDoc || editableRoot))
-      {
-        nsCOMPtr<nsISelection> selection;
-        selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                             getter_AddRefs(selection));
+    selCon->SetCaretReadOnly(mEditor->IsReadonly());
+    selCon->SetCaretEnabled(PR_TRUE);
+    selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
+    selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
 
-        nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-        if (presShell) {
-          nsRefPtr<nsCaret> caret = presShell->GetCaret();
-          if (caret) {
-            caret->SetIgnoreUserModify(PR_FALSE);
-            if (selection) {
-              caret->SetCaretDOMSelection(selection);
-            }
-          }
-        }
+    nsCOMPtr<nsISelectionPrivate> selectionPrivate =
+      do_QueryInterface(selection);
+    if (selectionPrivate)
+    {
+      selectionPrivate->SetAncestorLimiter(editableRoot);
+    }
 
-        selCon->SetCaretReadOnly(editor->IsReadonly());
-        selCon->SetCaretEnabled(PR_TRUE);
-        selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
-        selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
-
-        nsCOMPtr<nsISelectionPrivate> selectionPrivate =
-          do_QueryInterface(selection);
-        if (selectionPrivate)
-        {
-          selectionPrivate->SetAncestorLimiter(editableRoot);
-        }
-
-        if (selection && !editableRoot) {
-          PRInt32 rangeCount;
-          selection->GetRangeCount(&rangeCount);
-          if (rangeCount == 0) {
-            mEditor->BeginningOfDocument();
-          }
-        }
+    if (selection && !editableRoot) {
+      PRInt32 rangeCount;
+      selection->GetRangeCount(&rangeCount);
+      if (rangeCount == 0) {
+        mEditor->BeginningOfDocument();
       }
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  NS_ENSURE_ARG(aEvent);
+
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
   if (element)
     return NS_OK;
 
-  NS_ENSURE_ARG(aEvent);
   // turn off selection and caret
-  if (mEditor)
+  nsCOMPtr<nsISelectionController>selCon;
+  mEditor->GetSelectionController(getter_AddRefs(selCon));
+  if (selCon)
   {
-    nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
-    if (editor)
-    {
-      nsCOMPtr<nsISelectionController>selCon;
-      editor->GetSelectionController(getter_AddRefs(selCon));
-      if (selCon)
-      {
-        nsCOMPtr<nsISelection> selection;
-        selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                             getter_AddRefs(selection));
-
-        nsCOMPtr<nsISelectionPrivate> selectionPrivate =
-          do_QueryInterface(selection);
-        if (selectionPrivate) {
-          selectionPrivate->SetAncestorLimiter(nsnull);
-        }
+    nsCOMPtr<nsISelection> selection;
+    selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+                         getter_AddRefs(selection));
 
-        nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-        if (presShell) {
-          nsRefPtr<nsCaret> caret = presShell->GetCaret();
-          if (caret) {
-            caret->SetIgnoreUserModify(PR_TRUE);
-          }
-        }
-
-        selCon->SetCaretEnabled(PR_FALSE);
+    nsCOMPtr<nsISelectionPrivate> selectionPrivate =
+      do_QueryInterface(selection);
+    if (selectionPrivate) {
+      selectionPrivate->SetAncestorLimiter(nsnull);
+    }
 
-        nsEditor* editor = static_cast<nsEditor*>(mEditor);
-        if(editor->IsFormWidget() || editor->IsPasswordEditor() ||
-           editor->IsReadonly() || editor->IsDisabled() ||
-           editor->IsInputFiltered())
-        {
-          selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
-        }
-        else
-        {
-          selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
-        }
-
-        selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
+    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+    if (presShell) {
+      nsRefPtr<nsCaret> caret = presShell->GetCaret();
+      if (caret) {
+        caret->SetIgnoreUserModify(PR_TRUE);
       }
     }
+
+    selCon->SetCaretEnabled(PR_FALSE);
+
+    if(mEditor->IsFormWidget() || mEditor->IsPasswordEditor() ||
+       mEditor->IsReadonly() || mEditor->IsDisabled() ||
+       mEditor->IsInputFiltered())
+    {
+      selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
+    }
+    else
+    {
+      selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
+    }
+
+    selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
   }
 
   return NS_OK;
 }
 
--- a/editor/libeditor/base/nsEditorEventListener.h
+++ b/editor/libeditor/base/nsEditorEventListener.h
@@ -56,19 +56,23 @@ class nsPIDOMEventTarget;
 
 class nsEditorEventListener : public nsIDOMKeyListener,
                               public nsIDOMTextListener,
                               public nsIDOMCompositionListener,
                               public nsIDOMMouseListener,
                               public nsIDOMFocusListener
 {
 public:
-  nsEditorEventListener(nsEditor* aEditor);
+  nsEditorEventListener();
   virtual ~nsEditorEventListener();
 
+  virtual nsresult Connect(nsEditor* aEditor);
+
+  void Disconnect();
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
   // nsIDOMKeyListener
   NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
   NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
   NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
 
@@ -87,25 +91,28 @@ public:
   NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
 
   // nsIDOMFocusListener
   NS_IMETHOD Focus(nsIDOMEvent* aEvent);
   NS_IMETHOD Blur(nsIDOMEvent* aEvent);
 
 protected:
+  nsresult InstallToEditor();
+  void UninstallFromEditor();
+
   PRBool CanDrop(nsIDOMDragEvent* aEvent);
   nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
   nsresult DragOver(nsIDOMDragEvent* aDragEvent);
   nsresult DragLeave(nsIDOMDragEvent* aDragEvent);
   nsresult Drop(nsIDOMDragEvent* aDragEvent);
   nsresult DragGesture(nsIDOMDragEvent* aDragEvent);
   already_AddRefed<nsIPresShell> GetPresShell();
 
 protected:
-  nsIEditor* mEditor; // weak
+  nsEditor* mEditor; // weak
   nsRefPtr<nsCaret> mCaret;
   PRPackedBool mCaretDrawn;
   PRPackedBool mCommitText;
   PRPackedBool mInTransaction;
 };
 
 #endif // nsEditorEventListener_h__
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -331,21 +331,31 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc,
   return result;
 }
 
 nsresult
 nsHTMLEditor::CreateEventListeners()
 {
   NS_ENSURE_TRUE(!mEventListener, NS_ERROR_ALREADY_INITIALIZED);
   mEventListener = do_QueryInterface(
-    static_cast<nsIDOMKeyListener*>(new nsHTMLEditorEventListener(this)));
+    static_cast<nsIDOMKeyListener*>(new nsHTMLEditorEventListener()));
   NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
   return NS_OK;
 }
 
+nsresult
+nsHTMLEditor::InstallEventListeners()
+{
+  NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
+                 NS_ERROR_NOT_INITIALIZED);
+  nsHTMLEditorEventListener* listener =
+    reinterpret_cast<nsHTMLEditorEventListener*>(mEventListener.get());
+  return listener->Connect(this);
+}
+
 void
 nsHTMLEditor::RemoveEventListeners()
 {
   if (!mDocWeak)
   {
     return;
   }
 
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -424,16 +424,17 @@ public:
                        
 protected:
 
   NS_IMETHOD  InitRules();
 
   // Create the event listeners for the editor to install
   virtual nsresult CreateEventListeners();
 
+  virtual nsresult InstallEventListeners();
   virtual void RemoveEventListeners();
 
   // Return TRUE if aElement is a table-related elemet and caret was set
   PRBool SetCaretInTableCell(nsIDOMElement* aElement);
   PRBool IsElementInBody(nsIDOMElement* aElement);
 
   // inline style caching
   void ClearInlineStylesCache();
--- a/editor/libeditor/html/nsHTMLEditorEventListener.cpp
+++ b/editor/libeditor/html/nsHTMLEditorEventListener.cpp
@@ -33,267 +33,278 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "nsHTMLEditorEventListener.h"
+#include "nsHTMLEditor.h"
 #include "nsString.h"
 
 #include "nsIDOMEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsISelection.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMNSRange.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMHTMLTableElement.h"
 #include "nsIDOMHTMLTableCellElement.h"
 #include "nsIContent.h"
 
-#include "nsIEditor.h"
-#include "nsIHTMLEditor.h"
 #include "nsIHTMLObjectResizer.h"
 #include "nsEditProperty.h"
 #include "nsTextEditUtils.h"
 #include "nsHTMLEditUtils.h"
-#include "nsIHTMLInlineTableEditor.h"
 
 /*
  * nsHTMLEditorEventListener implementation
  *
  * The only reason we need this is so a context mouse-click
  *  moves the caret or selects an element as it does for normal click
  */
 
+#ifdef DEBUG
+nsresult
+nsHTMLEditorEventListener::Connect(nsEditor* aEditor)
+{
+  nsCOMPtr<nsIHTMLEditor> htmlEditor =
+    do_QueryInterface(static_cast<nsIEditor*>(aEditor));
+  nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor =
+    do_QueryInterface(static_cast<nsIEditor*>(aEditor));
+  NS_PRECONDITION(htmlEditor && htmlInlineTableEditor,
+                  "Set nsHTMLEditor or its sub class");
+  return nsEditorEventListener::Connect(aEditor);
+}
+#endif
+
+nsHTMLEditor*
+nsHTMLEditorEventListener::GetHTMLEditor()
+{
+  // mEditor must be nsHTMLEditor or its subclass.
+  return static_cast<nsHTMLEditor*>(mEditor);
+}
+
 NS_IMETHODIMP
 nsHTMLEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
   if (!mouseEvent) {
     //non-ui event passed in.  bad things.
     return NS_OK;
   }
 
-  // Don't do anything special if not an HTML editor
-  nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
-  if (htmlEditor)
-  {
-    nsCOMPtr<nsIDOMEventTarget> target;
-    nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
-    if (NS_FAILED(res)) return res;
-    if (!target) return NS_ERROR_NULL_POINTER;
-    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
+  nsHTMLEditor* htmlEditor = GetHTMLEditor();
 
-    nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor);
-    PRInt32 clientX, clientY;
-    mouseEvent->GetClientX(&clientX);
-    mouseEvent->GetClientY(&clientY);
-    objectResizer->MouseUp(clientX, clientY, element);
-  }
+  nsCOMPtr<nsIDOMEventTarget> target;
+  nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
+  if (NS_FAILED(res)) return res;
+  if (!target) return NS_ERROR_NULL_POINTER;
+  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
+
+  PRInt32 clientX, clientY;
+  mouseEvent->GetClientX(&clientX);
+  mouseEvent->GetClientY(&clientY);
+  htmlEditor->MouseUp(clientX, clientY, element);
 
   return nsEditorEventListener::MouseUp(aMouseEvent);
 }
 
 NS_IMETHODIMP
 nsHTMLEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
   if (!mouseEvent) {
     //non-ui event passed in.  bad things.
     return NS_OK;
   }
 
-  // Don't do anything special if not an HTML editor
-  nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
-  if (htmlEditor)
-  {
-    // Detect only "context menu" click
-    //XXX This should be easier to do!
-    // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-(
-    PRUint16 buttonNumber;
-    nsresult res = mouseEvent->GetButton(&buttonNumber);
-    if (NS_FAILED(res)) return res;
+  nsHTMLEditor* htmlEditor = GetHTMLEditor();
 
-    PRBool isContextClick;
+  // Detect only "context menu" click
+  //XXX This should be easier to do!
+  // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-(
+  PRUint16 buttonNumber;
+  nsresult res = mouseEvent->GetButton(&buttonNumber);
+  if (NS_FAILED(res)) return res;
+
+  PRBool isContextClick;
 
 #if defined(XP_MAC) || defined(XP_MACOSX)
-    // Ctrl+Click for context menu
-    res = mouseEvent->GetCtrlKey(&isContextClick);
-    if (NS_FAILED(res)) return res;
+  // Ctrl+Click for context menu
+  res = mouseEvent->GetCtrlKey(&isContextClick);
+  if (NS_FAILED(res)) return res;
 #else
-    // Right mouse button for Windows, UNIX
-    isContextClick = buttonNumber == 2;
+  // Right mouse button for Windows, UNIX
+  isContextClick = buttonNumber == 2;
 #endif
-    
-    PRInt32 clickCount;
-    res = mouseEvent->GetDetail(&clickCount);
+  
+  PRInt32 clickCount;
+  res = mouseEvent->GetDetail(&clickCount);
+  if (NS_FAILED(res)) return res;
+
+  nsCOMPtr<nsIDOMEventTarget> target;
+  nsCOMPtr<nsIDOMNSEvent> internalEvent = do_QueryInterface(aMouseEvent);
+  res = internalEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
+  if (NS_FAILED(res)) return res;
+  if (!target) return NS_ERROR_NULL_POINTER;
+  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
+
+  if (isContextClick || (buttonNumber == 0 && clickCount == 2))
+  {
+    nsCOMPtr<nsISelection> selection;
+    mEditor->GetSelection(getter_AddRefs(selection));
+    if (!selection) return NS_OK;
+
+    // Get location of mouse within target node
+    nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aMouseEvent);
+    if (!uiEvent) return NS_ERROR_FAILURE;
+
+    nsCOMPtr<nsIDOMNode> parent;
+    PRInt32 offset = 0;
+
+    res = uiEvent->GetRangeParent(getter_AddRefs(parent));
+    if (NS_FAILED(res)) return res;
+    if (!parent) return NS_ERROR_FAILURE;
+
+    res = uiEvent->GetRangeOffset(&offset);
     if (NS_FAILED(res)) return res;
 
-    nsCOMPtr<nsIDOMEventTarget> target;
-    nsCOMPtr<nsIDOMNSEvent> internalEvent = do_QueryInterface(aMouseEvent);
-    res = internalEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
-    if (NS_FAILED(res)) return res;
-    if (!target) return NS_ERROR_NULL_POINTER;
-    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
-
-    if (isContextClick || (buttonNumber == 0 && clickCount == 2))
+    // Detect if mouse point is within current selection for context click
+    PRBool nodeIsInSelection = PR_FALSE;
+    if (isContextClick)
     {
-      nsCOMPtr<nsISelection> selection;
-      mEditor->GetSelection(getter_AddRefs(selection));
-      if (!selection) return NS_OK;
+      PRBool isCollapsed;
+      selection->GetIsCollapsed(&isCollapsed);
+      if (!isCollapsed)
+      {
+        PRInt32 rangeCount;
+        res = selection->GetRangeCount(&rangeCount);
+        if (NS_FAILED(res)) return res;
 
-      // Get location of mouse within target node
-      nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aMouseEvent);
-      if (!uiEvent) return NS_ERROR_FAILURE;
-
-      nsCOMPtr<nsIDOMNode> parent;
-      PRInt32 offset = 0;
+        for (PRInt32 i = 0; i < rangeCount; i++)
+        {
+          nsCOMPtr<nsIDOMRange> range;
 
-      res = uiEvent->GetRangeParent(getter_AddRefs(parent));
-      if (NS_FAILED(res)) return res;
-      if (!parent) return NS_ERROR_FAILURE;
+          res = selection->GetRangeAt(i, getter_AddRefs(range));
+          if (NS_FAILED(res) || !range) 
+            continue;//don't bail yet, iterate through them all
 
-      res = uiEvent->GetRangeOffset(&offset);
-      if (NS_FAILED(res)) return res;
+          nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
+          if (NS_FAILED(res) || !nsrange) 
+            continue;//don't bail yet, iterate through them all
+
+          res = nsrange->IsPointInRange(parent, offset, &nodeIsInSelection);
 
-      // Detect if mouse point is within current selection for context click
-      PRBool nodeIsInSelection = PR_FALSE;
-      if (isContextClick)
+          // Done when we find a range that we are in
+          if (nodeIsInSelection)
+            break;
+        }
+      }
+    }
+    nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
+    if (node && !nodeIsInSelection)
+    {
+      if (!element)
       {
-        PRBool isCollapsed;
-        selection->GetIsCollapsed(&isCollapsed);
-        if (!isCollapsed)
+        if (isContextClick)
+        {
+          // Set the selection to the point under the mouse cursor:
+          selection->Collapse(parent, offset);
+        }
+        else
         {
-          PRInt32 rangeCount;
-          res = selection->GetRangeCount(&rangeCount);
+          // Get enclosing link if in text so we can select the link
+          nsCOMPtr<nsIDOMElement> linkElement;
+          res = htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"), node, getter_AddRefs(linkElement));
           if (NS_FAILED(res)) return res;
+          if (linkElement)
+            element = linkElement;
+        }
+      }
+      // Select entire element clicked on if NOT within an existing selection
+      //   and not the entire body, or table-related elements
+      if (element)
+      {
+        nsCOMPtr<nsIDOMNode> selectAllNode =
+          htmlEditor->FindUserSelectAllNode(element);
 
-          for (PRInt32 i = 0; i < rangeCount; i++)
+        if (selectAllNode)
+        {
+          nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
+          if (newElement)
           {
-            nsCOMPtr<nsIDOMRange> range;
-
-            res = selection->GetRangeAt(i, getter_AddRefs(range));
-            if (NS_FAILED(res) || !range) 
-              continue;//don't bail yet, iterate through them all
-
-            nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
-            if (NS_FAILED(res) || !nsrange) 
-              continue;//don't bail yet, iterate through them all
-
-            res = nsrange->IsPointInRange(parent, offset, &nodeIsInSelection);
-
-            // Done when we find a range that we are in
-            if (nodeIsInSelection)
-              break;
+            node = selectAllNode;
+            element = newElement;
           }
         }
-      }
-      nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
-      if (node && !nodeIsInSelection)
-      {
-        if (!element)
-        {
-          if (isContextClick)
-          {
-            // Set the selection to the point under the mouse cursor:
-            selection->Collapse(parent, offset);
-          }
-          else
-          {
-            // Get enclosing link if in text so we can select the link
-            nsCOMPtr<nsIDOMElement> linkElement;
-            res = htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"), node, getter_AddRefs(linkElement));
-            if (NS_FAILED(res)) return res;
-            if (linkElement)
-              element = linkElement;
-          }
-        }
-        // Select entire element clicked on if NOT within an existing selection
-        //   and not the entire body, or table-related elements
-        if (element)
-        {
-          // mEditor must be nsHTMLEditor, see the constructor.
-          nsCOMPtr<nsIDOMNode> selectAllNode =
-            reinterpret_cast<nsHTMLEditor*>(mEditor)->FindUserSelectAllNode(element);
-
-          if (selectAllNode)
-          {
-            nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
-            if (newElement)
-            {
-              node = selectAllNode;
-              element = newElement;
-            }
-          }
 
 // XXX: should we call nsHTMLEditUtils::IsTableElement here?
 // that also checks for thead, tbody, tfoot
-          if (nsTextEditUtils::IsBody(node) ||
-              nsHTMLEditUtils::IsTableCellOrCaption(node) ||
-              nsHTMLEditUtils::IsTableRow(node) ||
-              nsHTMLEditUtils::IsTable(node))
-          {
-            // This will place caret just inside table cell or at start of body
-            selection->Collapse(parent, offset);
-          }
-          else
-          {
-            htmlEditor->SelectElement(element);
-          }
+        if (nsTextEditUtils::IsBody(node) ||
+            nsHTMLEditUtils::IsTableCellOrCaption(node) ||
+            nsHTMLEditUtils::IsTableRow(node) ||
+            nsHTMLEditUtils::IsTable(node))
+        {
+          // This will place caret just inside table cell or at start of body
+          selection->Collapse(parent, offset);
+        }
+        else
+        {
+          htmlEditor->SelectElement(element);
         }
       }
-      // HACK !!! Context click places the caret but the context menu consumes
-      // the event; so we need to check resizing state ourselves
-      htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
+    }
+    // HACK !!! Context click places the caret but the context menu consumes
+    // the event; so we need to check resizing state ourselves
+    htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
 
-      // Prevent bubbling if we changed selection or 
-      //   for all context clicks
-      if (element || isContextClick)
-      {
-      #ifndef XP_OS2
-        mouseEvent->PreventDefault();
-      #endif
-        return NS_OK;
-      }
+    // Prevent bubbling if we changed selection or 
+    //   for all context clicks
+    if (element || isContextClick)
+    {
+    #ifndef XP_OS2
+      mouseEvent->PreventDefault();
+    #endif
+      return NS_OK;
     }
-    else if (!isContextClick && buttonNumber == 0 && clickCount == 1)
-    {
-      // if the target element is an image, we have to display resizers
-      nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor);
-      PRInt32 clientX, clientY;
-      mouseEvent->GetClientX(&clientX);
-      mouseEvent->GetClientY(&clientY);
-      objectResizer->MouseDown(clientX, clientY, element, aMouseEvent);
-    }
+  }
+  else if (!isContextClick && buttonNumber == 0 && clickCount == 1)
+  {
+    // if the target element is an image, we have to display resizers
+    PRInt32 clientX, clientY;
+    mouseEvent->GetClientX(&clientX);
+    mouseEvent->GetClientY(&clientY);
+    htmlEditor->MouseDown(clientX, clientY, element, aMouseEvent);
   }
 
   return nsEditorEventListener::MouseDown(aMouseEvent);
 }
 
 NS_IMETHODIMP
 nsHTMLEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
 {
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
   if (!mouseEvent) {
     //non-ui event passed in.  bad things.
     return NS_OK;
   }
 
-  // Don't do anything special if not an HTML inline table editor
-  nsCOMPtr<nsIHTMLInlineTableEditor> inlineTableEditing = do_QueryInterface(mEditor);
-  if (inlineTableEditing)
-  {
-    nsCOMPtr<nsIDOMEventTarget> target;
-    nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
-    if (NS_FAILED(res)) return res;
-    if (!target) return NS_ERROR_NULL_POINTER;
-    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
+  nsCOMPtr<nsIDOMEventTarget> target;
+  nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
+  if (NS_FAILED(res)) return res;
+  if (!target) return NS_ERROR_NULL_POINTER;
+  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
 
-    inlineTableEditing->DoInlineTableEditingAction(element);
-  }
+  GetHTMLEditor()->DoInlineTableEditingAction(element);
 
   return nsEditorEventListener::MouseClick(aMouseEvent);
 }
--- a/editor/libeditor/html/nsHTMLEditorEventListener.h
+++ b/editor/libeditor/html/nsHTMLEditorEventListener.h
@@ -36,29 +36,38 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsHTMLEditorEventListener_h__
 #define nsHTMLEditorEventListener_h__
 
 #include "nsEditorEventListener.h"
-#include "nsHTMLEditor.h"
+
+class nsHTMLEditor;
 
 class nsHTMLEditorEventListener : public nsEditorEventListener
 {
 public:
-  nsHTMLEditorEventListener(nsHTMLEditor* aEditor) :
-    nsEditorEventListener(aEditor)
+  nsHTMLEditorEventListener() :
+    nsEditorEventListener()
   {
   }
 
   virtual ~nsHTMLEditorEventListener()
   {
   }
 
+#ifdef DEBUG
+  // WARNING: You must be use nsHTMLEditor or its sub class for this class.
+  virtual nsresult Connect(nsEditor* aEditor);
+#endif
+
   NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
   NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
+
+protected:
+  inline nsHTMLEditor* GetHTMLEditor();
 };
 
 #endif // nsHTMLEditorEventListener_h__