Bug 1047588 - IMEContentObserver::Init() should take nsIEditor because nsDocShell sometimes hasn't been initialized and nsContentEditor::GetHTMLEditor() fails. r=smaug, a=lsblakk
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 05 Nov 2014 08:12:44 -0500
changeset 235136 2ec16d58f770f8d94281e1b35207d6932a60c5bc
parent 235135 975ffc36f1de91613357086b06aa90fead87c72c
child 235137 e62482d78bf0dfdaf39d0b4513ea881e698bc838
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, lsblakk
bugs1047588
milestone35.0a2
Bug 1047588 - IMEContentObserver::Init() should take nsIEditor because nsDocShell sometimes hasn't been initialized and nsContentEditor::GetHTMLEditor() fails. r=smaug, a=lsblakk
dom/events/IMEContentObserver.cpp
dom/events/IMEContentObserver.h
dom/events/IMEStateManager.cpp
dom/events/IMEStateManager.h
editor/libeditor/nsEditor.cpp
editor/libeditor/nsEditorEventListener.cpp
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -23,17 +23,16 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsISelectionController.h"
 #include "nsISelectionPrivate.h"
 #include "nsISupports.h"
-#include "nsITextControlElement.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
 #include "nsThreadUtils.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 
 using namespace widget;
@@ -94,48 +93,32 @@ IMEContentObserver::IMEContentObserver()
 #ifdef DEBUG
   TestMergingTextChangeData();
 #endif
 }
 
 void
 IMEContentObserver::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
-                         nsIContent* aContent)
+                         nsIContent* aContent,
+                         nsIEditor* aEditor)
 {
+  MOZ_ASSERT(aEditor, "aEditor must not be null");
+
   mESM = aPresContext->EventStateManager();
   mESM->OnStartToObserveContent(this);
 
   mWidget = aWidget;
   mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
   if (!mEditableNode) {
     return;
   }
 
-  nsCOMPtr<nsITextControlElement> textControlElement =
-    do_QueryInterface(mEditableNode);
-  if (textControlElement) {
-    // This may fail. For example, <input type="button" contenteditable>
-    mEditor = textControlElement->GetTextEditor();
-    if (!mEditor && mEditableNode->IsContent()) {
-      // The element must be an editing host.
-      nsIContent* editingHost = mEditableNode->AsContent()->GetEditingHost();
-      MOZ_ASSERT(editingHost == mEditableNode,
-                 "found editing host should be mEditableNode");
-      if (editingHost == mEditableNode) {
-        mEditor = nsContentUtils::GetHTMLEditor(aPresContext);
-      }
-    }
-  } else {
-    mEditor = nsContentUtils::GetHTMLEditor(aPresContext);
-  }
-  MOZ_ASSERT(mEditor, "Failed to get editor");
-  if (mEditor) {
-    mEditor->AddEditorObserver(this);
-  }
+  mEditor = aEditor;
+  mEditor->AddEditorObserver(this);
 
   nsIPresShell* presShell = aPresContext->PresShell();
 
   // get selection and root content
   nsCOMPtr<nsISelectionController> selCon;
   if (mEditableNode->IsNodeOfType(nsINode::eCONTENT)) {
     nsIFrame* frame =
       static_cast<nsIContent*>(mEditableNode.get())->GetPrimaryFrame();
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -59,17 +59,17 @@ public:
 
   // nsIScrollObserver
   virtual void ScrollPositionChanged() MOZ_OVERRIDE;
 
   bool OnMouseButtonEvent(nsPresContext* aPresContext,
                           WidgetMouseEvent* aMouseEvent);
 
   void Init(nsIWidget* aWidget, nsPresContext* aPresContext,
-            nsIContent* aContent);
+            nsIContent* aContent, nsIEditor* aEditor);
   void Destroy();
   /**
    * IMEContentObserver is stored by EventStateManager during observing.
    * DisconnectFromEventStateManager() is called when EventStateManager stops
    * storing the instance.
    */
   void DisconnectFromEventStateManager();
   bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -20,16 +20,17 @@
 #include "HTMLInputElement.h"
 #include "IMEContentObserver.h"
 
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMMouseEvent.h"
+#include "nsIEditor.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsINode.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsISupports.h"
 #include "nsPresContext.h"
@@ -554,22 +555,24 @@ IMEStateManager::OnClickInEditor(nsPresC
                             InputContextAction::FOCUS_NOT_CHANGED);
   IMEState newState = GetNewIMEState(aPresContext, aContent);
   SetIMEState(newState, aContent, widget, action);
 }
 
 // static
 void
 IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
-                                 nsIContent* aContent)
+                                 nsIContent* aContent,
+                                 nsIEditor* aEditor)
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
-    ("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p), "
-     "sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
-     aPresContext, aContent, sPresContext, sContent,
+    ("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, "
+     "aEditor=0x%p), sPresContext=0x%p, sContent=0x%p, "
+     "sActiveIMEContentObserver=0x%p",
+     aPresContext, aContent, aEditor, sPresContext, sContent,
      sActiveIMEContentObserver));
 
   if (sPresContext != aPresContext || sContent != aContent) {
     PR_LOG(sISMLog, PR_LOG_DEBUG,
       ("ISM:   IMEStateManager::OnFocusInEditor(), "
        "an editor not managed by ISM gets focus"));
     return;
   }
@@ -581,31 +584,32 @@ IMEStateManager::OnFocusInEditor(nsPresC
       PR_LOG(sISMLog, PR_LOG_DEBUG,
         ("ISM:   IMEStateManager::OnFocusInEditor(), "
          "the editor is already being managed by sActiveIMEContentObserver"));
       return;
     }
     DestroyIMEContentObserver();
   }
 
-  CreateIMEContentObserver();
+  CreateIMEContentObserver(aEditor);
 }
 
 // static
 void
 IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
-                                nsIContent* aContent)
+                                nsIContent* aContent,
+                                nsIEditor* aEditor)
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
     ("ISM: IMEStateManager::UpdateIMEState(aNewIMEState={ mEnabled=%s, "
-     "mOpen=%s }, aContent=0x%p), "
+     "mOpen=%s }, aContent=0x%p, aEditor=0x%p), "
      "sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
      "sIsGettingNewIMEState=%s",
      GetIMEStateEnabledName(aNewIMEState.mEnabled),
-     GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent,
+     GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, aEditor,
      sPresContext, sContent, sActiveIMEContentObserver,
      GetBoolName(sIsGettingNewIMEState)));
 
   if (sIsGettingNewIMEState) {
     PR_LOG(sISMLog, PR_LOG_DEBUG,
       ("ISM:   IMEStateManager::UpdateIMEState(), "
        "does nothing because of called while getting new IME state"));
     return;
@@ -646,17 +650,17 @@ IMEStateManager::UpdateIMEState(const IM
 
   if (updateIMEState) {
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::FOCUS_NOT_CHANGED);
     SetIMEState(aNewIMEState, aContent, widget, action);
   }
 
   if (createTextStateManager) {
-    CreateIMEContentObserver();
+    CreateIMEContentObserver(aEditor);
   }
 }
 
 // static
 IMEState
 IMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
                                 nsIContent*    aContent)
 {
@@ -1140,23 +1144,23 @@ IMEStateManager::DestroyIMEContentObserv
      "the active IMEContentObserver..."));
   nsRefPtr<IMEContentObserver> tsm;
   tsm.swap(sActiveIMEContentObserver);
   tsm->Destroy();
 }
 
 // static
 void
-IMEStateManager::CreateIMEContentObserver()
+IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
 {
   PR_LOG(sISMLog, PR_LOG_ALWAYS,
-    ("ISM: IMEStateManager::CreateIMEContentObserver(), "
+    ("ISM: IMEStateManager::CreateIMEContentObserver(aEditor=0x%p), "
      "sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
      "sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
-     sPresContext, sContent, sActiveIMEContentObserver,
+     aEditor, sPresContext, sContent, sActiveIMEContentObserver,
      GetBoolName(sActiveIMEContentObserver ?
        sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
 
   if (NS_WARN_IF(sActiveIMEContentObserver)) {
     PR_LOG(sISMLog, PR_LOG_ERROR,
       ("ISM:   IMEStateManager::CreateIMEContentObserver(), FAILED due to "
        "there is already an active IMEContentObserver"));
     MOZ_ASSERT(sActiveIMEContentObserver->IsManaging(sPresContext, sContent));
@@ -1190,17 +1194,17 @@ IMEStateManager::CreateIMEContentObserve
      "IMEContentObserver instance..."));
   sActiveIMEContentObserver = new IMEContentObserver();
   NS_ADDREF(sActiveIMEContentObserver);
 
   // IMEContentObserver::Init() might create another IMEContentObserver
   // instance.  So, sActiveIMEContentObserver would be replaced with new one.
   // We should hold the current instance here.
   nsRefPtr<IMEContentObserver> kungFuDeathGrip(sActiveIMEContentObserver);
-  sActiveIMEContentObserver->Init(widget, sPresContext, sContent);
+  sActiveIMEContentObserver->Init(widget, sPresContext, sContent, aEditor);
 }
 
 // static
 nsresult
 IMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSelection,
                                           nsIContent** aRootContent)
 {
   if (!sActiveIMEContentObserver) {
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -6,16 +6,17 @@
 #ifndef mozilla_IMEStateManager_h_
 #define mozilla_IMEStateManager_h_
 
 #include "mozilla/EventForwards.h"
 #include "nsIWidget.h"
 
 class nsIContent;
 class nsIDOMMouseEvent;
+class nsIEditor;
 class nsINode;
 class nsPIDOMWindow;
 class nsPresContext;
 class nsISelection;
 
 namespace mozilla {
 
 class EventDispatchingCallback;
@@ -60,17 +61,18 @@ public:
   // Get the focused editor's selection and root
   static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
                                            nsIContent** aRoot);
   // This method updates the current IME state.  However, if the enabled state
   // isn't changed by the new state, this method does nothing.
   // Note that this method changes the IME state of the active element in the
   // widget.  So, the caller must have focus.
   static void UpdateIMEState(const IMEState &aNewIMEState,
-                             nsIContent* aContent);
+                             nsIContent* aContent,
+                             nsIEditor* aEditor);
 
   // This method is called when user operates mouse button in focused editor
   // and before the editor handles it.
   // Returns true if IME consumes the event.  Otherwise, false.
   static bool OnMouseButtonEventInEditor(nsPresContext* aPresContext,
                                          nsIContent* aContent,
                                          nsIDOMMouseEvent* aMouseEvent);
 
@@ -84,17 +86,18 @@ public:
                               nsIDOMMouseEvent* aMouseEvent);
 
   // This method is called when editor actually gets focus.
   // aContent must be:
   //   If the editor is for <input> or <textarea>, the element.
   //   If the editor is for contenteditable, the active editinghost.
   //   If the editor is for designMode, nullptr.
   static void OnFocusInEditor(nsPresContext* aPresContext,
-                              nsIContent* aContent);
+                              nsIContent* aContent,
+                              nsIEditor* aEditor);
 
   /**
    * All composition events must be dispatched via DispatchCompositionEvent()
    * for storing the composition target and ensuring a set of composition
    * events must be fired the stored target.  If the stored composition event
    * target is destroying, this removes the stored composition automatically.
    */
   static void DispatchCompositionEvent(
@@ -144,17 +147,17 @@ protected:
   static void SetIMEState(const IMEState &aState,
                           nsIContent* aContent,
                           nsIWidget* aWidget,
                           InputContextAction aAction);
   static IMEState GetNewIMEState(nsPresContext* aPresContext,
                                  nsIContent* aContent);
 
   static void EnsureTextCompositionArray();
-  static void CreateIMEContentObserver();
+  static void CreateIMEContentObserver(nsIEditor* aEditor);
   static void DestroyIMEContentObserver();
 
   static bool IsEditable(nsINode* node);
 
   static bool IsEditableIMEState(nsIWidget* aWidget);
 
   static nsIContent*    sContent;
   static nsPresContext* sPresContext;
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -313,17 +313,17 @@ nsEditor::PostCreate()
     nsEditorEventListener* listener =
       reinterpret_cast<nsEditorEventListener*> (mEventListener.get());
     listener->SpellCheckIfNeeded();
 
     IMEState newState;
     rv = GetPreferredIMEState(&newState);
     NS_ENSURE_SUCCESS(rv, NS_OK);
     nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
-    IMEStateManager::UpdateIMEState(newState, content);
+    IMEStateManager::UpdateIMEState(newState, content, this);
   }
   return NS_OK;
 }
 
 /* virtual */
 void
 nsEditor::CreateEventListeners()
 {
@@ -494,17 +494,17 @@ nsEditor::SetFlags(uint32_t aFlags)
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
     IMEState newState;
     nsresult rv = GetPreferredIMEState(&newState);
     if (NS_SUCCEEDED(rv)) {
       // NOTE: When the enabled state isn't going to be modified, this method
       // is going to do nothing.
       nsCOMPtr<nsIContent> content = GetFocusedContentForIME();
-      IMEStateManager::UpdateIMEState(newState, content);
+      IMEStateManager::UpdateIMEState(newState, content, this);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditor::GetIsSelectionEditable(bool *aIsSelectionEditable)
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -1095,17 +1095,18 @@ nsEditorEventListener::Focus(nsIDOMEvent
     }
   }
 
   mEditor->OnFocus(target);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_OK);
   nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
-  IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent);
+  IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
+                                   mEditor);
 
   return NS_OK;
 }
 
 nsresult
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(aEvent, NS_OK);