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 111467 795511f1212df5c254b47aae900137fbe085ffef
parent 111466 f5e702c39521bb6fb440664593d7dbcbd5bf3da8
child 111468 4380bab9db045aae4006c0442e6433d1337f6c44
push id23748
push userryanvm@gmail.com
push dateFri, 26 Oct 2012 11:29:12 +0000
treeherdermozilla-central@8586bd350875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs805306
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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);