Bug 805306 Get rid of nsIMEStateManager::OnTextStateBlur() and nsIMEStateManager::OnTextStateFocus() r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 26 Oct 2012 09:49:13 +0900
changeset 111599 795511f1212df5c254b47aae900137fbe085ffef
parent 111598 f5e702c39521bb6fb440664593d7dbcbd5bf3da8
child 111600 4380bab9db045aae4006c0442e6433d1337f6c44
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerssmaug
bugs805306
milestone19.0a1
Bug 805306 Get rid of nsIMEStateManager::OnTextStateBlur() and nsIMEStateManager::OnTextStateFocus() r=smaug
content/events/src/nsIMEStateManager.cpp
content/events/src/nsIMEStateManager.h
dom/base/nsFocusManager.cpp
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditorEventListener.cpp
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -35,16 +35,51 @@
 #include "nsHTMLFormElement.h"
 #include "mozilla/Attributes.h"
 #include "nsEventDispatcher.h"
 #include "TextComposition.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
+// nsTextStateManager notifies widget of any text and selection changes
+//  in the currently focused editor
+// sTextStateObserver points to the currently active nsTextStateManager
+// sTextStateObserver is null if there is no focused editor
+
+class nsTextStateManager MOZ_FINAL : public nsISelectionListener,
+                                     public nsStubMutationObserver
+{
+public:
+  nsTextStateManager();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISELECTIONLISTENER
+  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+  nsresult Init(nsIWidget* aWidget,
+                nsPresContext* aPresContext,
+                nsINode* aNode,
+                bool aWantUpdates);
+  void     Destroy(void);
+  bool     IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
+
+  nsCOMPtr<nsIWidget>            mWidget;
+  nsCOMPtr<nsISelection>         mSel;
+  nsCOMPtr<nsIContent>           mRootContent;
+  nsCOMPtr<nsINode>              mEditableNode;
+  bool                           mDestroying;
+
+private:
+  void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
+};
+
 /******************************************************************/
 /* nsIMEStateManager                                              */
 /******************************************************************/
 
 nsIContent*    nsIMEStateManager::sContent      = nullptr;
 nsPresContext* nsIMEStateManager::sPresContext  = nullptr;
 bool           nsIMEStateManager::sInstalledMenuKeyboardListener = false;
 bool           nsIMEStateManager::sInSecureInputMode = false;
@@ -83,17 +118,17 @@ nsIMEStateManager::OnDestroyPresContext(
   if (widget) {
     IMEState newState = GetNewIMEState(sPresContext, nullptr);
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::LOST_FOCUS);
     SetIMEState(newState, nullptr, widget, action);
   }
   NS_IF_RELEASE(sContent);
   sPresContext = nullptr;
-  OnTextStateBlur(nullptr, nullptr);
+  DestroyTextStateManager();
   return NS_OK;
 }
 
 nsresult
 nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
                                    nsIContent* aContent)
 {
   NS_ENSURE_ARG_POINTER(aPresContext);
@@ -143,16 +178,17 @@ nsIMEStateManager::OnRemoveContent(nsPre
     IMEState newState = GetNewIMEState(sPresContext, nullptr);
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::LOST_FOCUS);
     SetIMEState(newState, nullptr, widget, action);
   }
 
   NS_IF_RELEASE(sContent);
   sPresContext = nullptr;
+  DestroyTextStateManager();
 
   return NS_OK;
 }
 
 nsresult
 nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
                                  nsIContent* aContent,
                                  InputContextAction::Cause aCause)
@@ -161,17 +197,24 @@ nsIMEStateManager::OnChangeFocus(nsPresC
   return OnChangeFocusInternal(aPresContext, aContent, action);
 }
 
 nsresult
 nsIMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
                                          nsIContent* aContent,
                                          InputContextAction aAction)
 {
-  NS_ENSURE_ARG_POINTER(aPresContext);
+  if (sTextStateObserver &&
+      !sTextStateObserver->IsManaging(aPresContext, aContent)) {
+    DestroyTextStateManager();
+  }
+
+  if (!aPresContext) {
+    return NS_OK;
+  }
 
   nsCOMPtr<nsIWidget> widget = aPresContext->GetNearestWidget();
   if (!widget) {
     return NS_OK;
   }
 
   // Handle secure input mode for password field input.
   bool contentIsPassword = false;
@@ -230,16 +273,19 @@ nsIMEStateManager::OnChangeFocusInternal
   SetIMEState(newState, aContent, widget, aAction);
 
   sPresContext = aPresContext;
   if (sContent != aContent) {
     NS_IF_RELEASE(sContent);
     NS_IF_ADDREF(sContent = aContent);
   }
 
+  // Don't call CreateTextStateManager() here, it should be called from
+  // focus event handler of editor.
+
   return NS_OK;
 }
 
 void
 nsIMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling)
 {
   sInstalledMenuKeyboardListener = aInstalling;
 
@@ -284,16 +330,27 @@ nsIMEStateManager::OnClickInEditor(nsPre
 
   InputContextAction action(InputContextAction::CAUSE_MOUSE,
                             InputContextAction::FOCUS_NOT_CHANGED);
   IMEState newState = GetNewIMEState(aPresContext, aContent);
   SetIMEState(newState, aContent, widget, action);
 }
 
 void
+nsIMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
+                                   nsIContent* aContent)
+{
+  if (sPresContext != aPresContext || sContent != aContent) {
+    return;
+  }
+
+  CreateTextStateManager();
+}
+
+void
 nsIMEStateManager::UpdateIMEState(const IMEState &aNewIMEState,
                                   nsIContent* aContent)
 {
   if (!sPresContext) {
     NS_WARNING("ISM doesn't know which editor has focus");
     return;
   }
   nsCOMPtr<nsIWidget> widget = sPresContext->GetNearestWidget();
@@ -306,19 +363,23 @@ nsIMEStateManager::UpdateIMEState(const 
   InputContext context = widget->GetInputContext();
   if (context.mIMEState.mEnabled == aNewIMEState.mEnabled) {
     return;
   }
 
   // commit current composition
   NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
 
+  DestroyTextStateManager();
+
   InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                             InputContextAction::FOCUS_NOT_CHANGED);
   SetIMEState(aNewIMEState, aContent, widget, action);
+
+  CreateTextStateManager();
 }
 
 IMEState
 nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
                                   nsIContent*    aContent)
 {
   // On Printing or Print Preview, we don't need IME.
   if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
@@ -582,51 +643,16 @@ nsIMEStateManager::NotifyIME(Notificatio
 
   nsIWidget* widget = aPresContext->GetNearestWidget();
   if (!widget) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   return NotifyIME(aNotification, widget);
 }
 
-
-// nsTextStateManager notifies widget of any text and selection changes
-//  in the currently focused editor
-// sTextStateObserver points to the currently active nsTextStateManager
-// sTextStateObserver is null if there is no focused editor
-
-class nsTextStateManager MOZ_FINAL : public nsISelectionListener,
-                                     public nsStubMutationObserver
-{
-public:
-  nsTextStateManager();
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSISELECTIONLISTENER
-  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-
-  nsresult Init(nsIWidget* aWidget,
-                nsPresContext* aPresContext,
-                nsINode* aNode,
-                bool aWantUpdates);
-  void     Destroy(void);
-
-  nsCOMPtr<nsIWidget>            mWidget;
-  nsCOMPtr<nsISelection>         mSel;
-  nsCOMPtr<nsIContent>           mRootContent;
-  nsCOMPtr<nsINode>              mEditableNode;
-  bool                           mDestroying;
-
-private:
-  void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
-};
-
 nsTextStateManager::nsTextStateManager()
 {
   mDestroying = false;
 }
 
 nsresult
 nsTextStateManager::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
@@ -707,16 +733,25 @@ nsTextStateManager::Destroy(void)
   if (mRootContent) {
     mRootContent->RemoveMutationObserver(this);
     mRootContent = nullptr;
   }
   mEditableNode = nullptr;
   mWidget = nullptr;
 }
 
+bool
+nsTextStateManager::IsManaging(nsPresContext* aPresContext,
+                                  nsIContent* aContent)
+{
+  return !mDestroying &&
+    mEditableNode == nsIMEStateManager::GetRootEditableNode(aPresContext,
+                                                            aContent);
+}
+
 NS_IMPL_ISUPPORTS2(nsTextStateManager,
                    nsIMutationObserver,
                    nsISelectionListener)
 
 // Helper class, used for selection change notification
 class SelectionChangeEvent : public nsRunnable {
 public:
   SelectionChangeEvent(nsIWidget *widget)
@@ -862,29 +897,32 @@ nsTextStateManager::ContentRemoved(nsIDo
     return;
 
   // fire notification
   if (childOffset)
     nsContentUtils::AddScriptRunner(
         new TextChangeEvent(mWidget, offset, offset + childOffset, offset));
 }
 
-static bool IsEditable(nsINode* node) {
+bool
+nsIMEStateManager::IsEditable(nsINode* node)
+{
   if (node->IsEditable()) {
     return true;
   }
   // |node| might be readwrite (for example, a text control)
   if (node->IsElement() && node->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
     return true;
   }
   return false;
 }
 
-static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
-                                    nsIContent* aContent)
+nsINode*
+nsIMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
+                                       nsIContent* aContent)
 {
   if (aContent) {
     nsINode* root = nullptr;
     nsINode* node = aContent;
     while (node && IsEditable(node)) {
       root = node;
       node = node->GetParentNode();
     }
@@ -893,78 +931,81 @@ static nsINode* GetRootEditableNode(nsPr
   if (aPresContext) {
     nsIDocument* document = aPresContext->Document();
     if (document && document->IsEditable())
       return document;
   }
   return nullptr;
 }
 
-nsresult
-nsIMEStateManager::OnTextStateBlur(nsPresContext* aPresContext,
-                                   nsIContent* aContent)
+void
+nsIMEStateManager::DestroyTextStateManager()
 {
-  if (!sTextStateObserver || sTextStateObserver->mDestroying ||
-      sTextStateObserver->mEditableNode ==
-          GetRootEditableNode(aPresContext, aContent))
-    return NS_OK;
+  if (!sTextStateObserver || sTextStateObserver->mDestroying) {
+    return;
+  }
 
   sTextStateObserver->mDestroying = true;
   sTextStateObserver->mWidget->OnIMEFocusChange(false);
   sTextStateObserver->Destroy();
   NS_RELEASE(sTextStateObserver);
-  return NS_OK;
 }
 
-nsresult
-nsIMEStateManager::OnTextStateFocus(nsPresContext* aPresContext,
-                                    nsIContent* aContent)
+void
+nsIMEStateManager::CreateTextStateManager()
 {
-  if (sTextStateObserver) return NS_OK;
-
-  nsINode *editableNode = GetRootEditableNode(aPresContext, aContent);
-  if (!editableNode) return NS_OK;
+  if (sTextStateObserver) {
+    NS_WARNING("text state observer has been there already");
+    MOZ_ASSERT(sTextStateObserver->IsManaging(sPresContext, sContent));
+    return;
+  }
 
-  nsIPresShell* shell = aPresContext->GetPresShell();
-  NS_ENSURE_TRUE(shell, NS_ERROR_NOT_AVAILABLE);
-  
-  nsIViewManager* vm = shell->GetViewManager();
-  NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIWidget> widget;
-  nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
+  nsCOMPtr<nsIWidget> widget = sPresContext->GetNearestWidget();
   if (!widget) {
-    return NS_OK; // Sometimes, there are no widgets.
+    return; // Sometimes, there are no widgets.
   }
 
-  rv = widget->OnIMEFocusChange(true);
+  // If it's not text ediable, we don't need to create nsTextStateManager.
+  switch (widget->GetInputContext().mIMEState.mEnabled) {
+    case widget::IMEState::ENABLED:
+    case widget::IMEState::PASSWORD:
+      break;
+    default:
+      return;
+  }
+
+  nsINode *editableNode = GetRootEditableNode(sPresContext, sContent);
+  if (!editableNode) {
+    return;
+  }
+
+  nsresult rv = widget->OnIMEFocusChange(true);
   if (rv == NS_ERROR_NOT_IMPLEMENTED)
-    return NS_OK;
-  NS_ENSURE_SUCCESS(rv, rv);
+    return;
+  NS_ENSURE_SUCCESS_VOID(rv);
 
   bool wantUpdates = rv != NS_SUCCESS_IME_NO_UPDATES;
 
   // OnIMEFocusChange may cause focus and sTextStateObserver to change
   // In that case return and keep the current sTextStateObserver
-  NS_ENSURE_TRUE(!sTextStateObserver, NS_OK);
+  NS_ENSURE_TRUE_VOID(!sTextStateObserver);
 
   sTextStateObserver = new nsTextStateManager();
-  NS_ENSURE_TRUE(sTextStateObserver, NS_ERROR_OUT_OF_MEMORY);
+  NS_ENSURE_TRUE_VOID(sTextStateObserver);
   NS_ADDREF(sTextStateObserver);
-  rv = sTextStateObserver->Init(widget, aPresContext,
+  rv = sTextStateObserver->Init(widget, sPresContext,
                                 editableNode, wantUpdates);
-  if (NS_FAILED(rv)) {
-    sTextStateObserver->mDestroying = true;
-    sTextStateObserver->Destroy();
-    NS_RELEASE(sTextStateObserver);
-    widget->OnIMEFocusChange(false);
-    return rv;
+  if (NS_SUCCEEDED(rv)) {
+    return;
   }
-  return NS_OK;
+
+  sTextStateObserver->mDestroying = true;
+  sTextStateObserver->Destroy();
+  NS_RELEASE(sTextStateObserver);
+  widget->OnIMEFocusChange(false);
 }
 
 nsresult
 nsIMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSel,
                                             nsIContent** aRoot)
 {
   if (!sTextStateObserver || !sTextStateObserver->mEditableNode ||
       !sTextStateObserver->mSel)
--- a/content/events/src/nsIMEStateManager.h
+++ b/content/events/src/nsIMEStateManager.h
@@ -24,52 +24,42 @@ class TextCompositionArray;
 } // namespace mozilla
 
 /*
  * IME state manager
  */
 
 class nsIMEStateManager
 {
+  friend class nsTextStateManager;
 protected:
   typedef mozilla::widget::IMEState IMEState;
   typedef mozilla::widget::InputContext InputContext;
   typedef mozilla::widget::InputContextAction InputContextAction;
 
 public:
   static void Shutdown();
 
   static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
   static nsresult OnRemoveContent(nsPresContext* aPresContext,
                                   nsIContent* aContent);
   /**
    * OnChangeFocus() should be called when focused content is changed or
-   * IME enabled state is changed.  If focus isn't actually changed and IME
-   * enabled state isn't changed, this will do nothing.
+   * IME enabled state is changed.  If nobody has focus, set both aPresContext
+   * and aContent nullptr.  E.g., all windows are deactivated.
    */
   static nsresult OnChangeFocus(nsPresContext* aPresContext,
                                 nsIContent* aContent,
                                 InputContextAction::Cause aCause);
   static void OnInstalledMenuKeyboardListener(bool aInstalling);
 
   // These two methods manage focus and selection/text observers.
   // They are separate from OnChangeFocus above because this offers finer
   // control compared to having the two methods incorporated into OnChangeFocus
 
-  // OnTextStateBlur should be called *before* NS_BLUR_CONTENT fires
-  // aPresContext is the nsPresContext receiving focus (not lost focus)
-  // aContent is the nsIContent receiving focus (not lost focus)
-  // aPresContext and/or aContent may be null
-  static nsresult OnTextStateBlur(nsPresContext* aPresContext,
-                                  nsIContent* aContent);
-  // OnTextStateFocus should be called *after* NS_FOCUS_CONTENT fires
-  // aPresContext is the nsPresContext receiving focus
-  // aContent is the nsIContent receiving focus
-  static nsresult OnTextStateFocus(nsPresContext* aPresContext,
-                                   nsIContent* aContent);
   // 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,
@@ -79,16 +69,24 @@ public:
   // 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, NULL.
   static void OnClickInEditor(nsPresContext* aPresContext,
                               nsIContent* aContent,
                               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, NULL.
+  static void OnFocusInEditor(nsPresContext* aPresContext,
+                              nsIContent* aContent);
+
   /**
    * All DOM composition events and DOM text 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(nsINode* aEventTargetNode,
@@ -113,16 +111,22 @@ 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 CreateTextStateManager();
+  static void DestroyTextStateManager();
+
+  static bool IsEditable(nsINode* node);
+  static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
+                                      nsIContent* aContent);
 
   static nsIContent*    sContent;
   static nsPresContext* sPresContext;
   static bool           sInstalledMenuKeyboardListener;
   static bool           sInSecureInputMode;
 
   static nsTextStateManager* sTextStateObserver;
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -948,20 +948,21 @@ nsFocusManager::WindowHidden(nsIDOMWindo
 
     if (presShell) {
       SendFocusOrBlurEvent(NS_BLUR_CONTENT, presShell,
                            oldFocusedContent->GetCurrentDoc(),
                            oldFocusedContent, 1, false);
     }
   }
 
-  nsIMEStateManager::OnTextStateBlur(nullptr, nullptr);
+  nsPresContext* focusedPresContext =
+    presShell ? presShell->GetPresContext() : nullptr;
+  nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
+                                   GetFocusMoveActionCause(0));
   if (presShell) {
-    nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
-                                     GetFocusMoveActionCause(0));
     SetCaretVisible(presShell, false, nullptr);
   }
 
   // if the docshell being hidden is being destroyed, then we want to move
   // focus somewhere else. Call ClearFocus on the toplevel window, which
   // will have the effect of clearing the focus and moving the focused window
   // to the toplevel window. But if the window isn't being destroyed, we are
   // likely just loading a new document in it, so we want to maintain the
@@ -1530,24 +1531,20 @@ nsFocusManager::Blur(nsPIDOMWindow* aWin
   }
 
   bool clearFirstBlurEvent = false;
   if (!mFirstBlurEvent) {
     mFirstBlurEvent = content;
     clearFirstBlurEvent = true;
   }
 
-  // if there is still an active window, adjust the IME state.
-  // This has to happen before the focus is cleared below, otherwise, the IME
-  // compositionend event won't get fired at the element being blurred.
-  nsIMEStateManager::OnTextStateBlur(nullptr, nullptr);
-  if (mActiveWindow) {
-    nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
-                                     GetFocusMoveActionCause(0));
-  }
+  nsPresContext* focusedPresContext =
+    mActiveWindow ? presShell->GetPresContext() : nullptr;
+  nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
+                                   GetFocusMoveActionCause(0));
 
   // now adjust the actual focus, by clearing the fields in the focus manager
   // and in the window.
   mFocusedContent = nullptr;
   bool shouldShowFocusRing = window->ShouldShowFocusRing();
   if (aWindowToClear)
     aWindowToClear->SetFocusedNode(nullptr);
 
@@ -1810,20 +1807,17 @@ nsFocusManager::Focus(nsPIDOMWindow* aWi
       // XXXndeakin P2 someone could adjust the focus during the update
       if (!aWindowRaised)
         aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
 
       SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell,
                            aContent->GetCurrentDoc(),
                            aContent, aFlags & FOCUSMETHOD_MASK,
                            aWindowRaised, isRefocus);
-
-      nsIMEStateManager::OnTextStateFocus(presContext, aContent);
     } else {
-      nsIMEStateManager::OnTextStateBlur(presContext, nullptr);
       nsIMEStateManager::OnChangeFocus(presContext, nullptr,
                                        GetFocusMoveActionCause(aFlags));
       if (!aWindowRaised) {
         aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
       }
     }
   }
   else {
@@ -1838,17 +1832,16 @@ nsFocusManager::Focus(nsPIDOMWindow* aWi
         nsCOMPtr<nsIWidget> widget;
         vm->GetRootWidget(getter_AddRefs(widget));
         if (widget)
           widget->SetFocus(false);
       }
     }
 
     nsPresContext* presContext = presShell->GetPresContext();
-    nsIMEStateManager::OnTextStateBlur(presContext, nullptr);
     nsIMEStateManager::OnChangeFocus(presContext, nullptr,
                                      GetFocusMoveActionCause(aFlags));
 
     if (!aWindowRaised)
       aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
   }
 
   // update the caret visibility and position to match the newly focused
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -309,18 +309,18 @@ nsEditor::PostCreate()
   // update nsTextStateManager and caret if we have focus
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     NS_ASSERTION(ps, "no pres shell even though we have focus");
     NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED);
     nsPresContext* pc = ps->GetPresContext(); 
 
-    nsIMEStateManager::OnTextStateBlur(pc, nullptr);
-    nsIMEStateManager::OnTextStateFocus(pc, focusedContent);
+    nsIMEStateManager::OnChangeFocus(pc, focusedContent,
+                                     InputContextAction::CAUSE_UNKNOWN);
 
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(focusedContent);
     if (target) {
       InitializeSelection(target);
     }
 
     // If the text control gets reframed during focus, Focus() would not be
     // called, so take a chance here to see if we need to spell check the text
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -896,16 +896,26 @@ nsEditorEventListener::Focus(nsIDOMEvent
       nsCOMPtr<nsIDOMElement> element;
       fm->GetFocusedElement(getter_AddRefs(element));
       if (!SameCOMIdentity(element, target))
         return NS_OK;
     }
   }
 
   mEditor->OnFocus(target);
+
+  nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContent();
+  NS_ENSURE_TRUE(focusedContent, NS_OK);
+  nsIDocument* currentDoc = focusedContent->GetCurrentDoc();
+  NS_ENSURE_TRUE(currentDoc, NS_OK);
+  nsCOMPtr<nsIPresShell> ps = GetPresShell();
+  NS_ENSURE_TRUE(ps, NS_OK);
+  nsIMEStateManager::OnFocusInEditor(ps->GetPresContext(),
+    currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_ARG(aEvent);