Bug 1377672 - part2: IMEStateManager::SetIMEState() should set input context with proper origin information r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 03 Jul 2017 12:28:10 +0900
changeset 605193 2f01e62d6867ae1c79aed7c9fdc9b1087a842092
parent 605192 0519b4d9316496de963db53597b28598ec0f3d92
child 605194 faa5e384a7e166d9d7ea46aa0ef89b1e6c8dc652
push id67319
push usermasayuki@d-toybox.com
push dateFri, 07 Jul 2017 05:35:43 +0000
reviewersm_kato
bugs1377672
milestone56.0a1
Bug 1377672 - part2: IMEStateManager::SetIMEState() should set input context with proper origin information r?m_kato Currently, IMEStateManager always sets input context as set by current process even when it needs to adjust IME state when a tab parent for current focused IME process is removed. Then, input context for the widget is marked as for main process but the widget still have IME focus of a remote process. For fixing this mismatch, IMEStateManager should set ORIGIN_CONTENT even when the tab parent is being destroyed. MozReview-Commit-ID: C10YOAtkET4
dom/events/IMEStateManager.cpp
dom/events/IMEStateManager.h
widget/IMEData.h
widget/nsBaseWidget.cpp
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -139,16 +139,17 @@ GetIMEStateSetOpenName(IMEState::Open aO
 StaticRefPtr<nsIContent> IMEStateManager::sContent;
 StaticRefPtr<nsPresContext> IMEStateManager::sPresContext;
 nsIWidget* IMEStateManager::sWidget = nullptr;
 nsIWidget* IMEStateManager::sFocusedIMEWidget = nullptr;
 nsIWidget* IMEStateManager::sActiveInputContextWidget = nullptr;
 StaticRefPtr<TabParent> IMEStateManager::sActiveTabParent;
 StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
 TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
+InputContext::Origin IMEStateManager::sOrigin = InputContext::ORIGIN_MAIN;
 bool IMEStateManager::sInstalledMenuKeyboardListener = false;
 bool IMEStateManager::sIsGettingNewIMEState = false;
 bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
 bool IMEStateManager::sInputModeSupported = false;
 bool IMEStateManager::sRemoteHasFocus = false;
 
 // static
 void
@@ -158,16 +159,19 @@ IMEStateManager::Init()
     &sCheckForIMEUnawareWebApps,
     "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
     false);
 
   Preferences::AddBoolVarCache(
     &sInputModeSupported,
     "dom.forms.inputmode",
     false);
+
+  sOrigin = XRE_IsParentProcess() ? InputContext::ORIGIN_MAIN :
+                                    InputContext::ORIGIN_CONTENT;
 }
 
 // static
 void
 IMEStateManager::Shutdown()
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("Shutdown(), sTextCompositions=0x%p, sTextCompositions->Length()=%" PRIuSIZE,
@@ -299,17 +303,19 @@ IMEStateManager::OnDestroyPresContext(ns
      aPresContext, sPresContext.get(), sContent.get(), sTextCompositions));
 
   DestroyIMEContentObserver();
 
   if (sWidget) {
     IMEState newState = GetNewIMEState(sPresContext, nullptr);
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::LOST_FOCUS);
-    SetIMEState(newState, nullptr, sWidget, action);
+    InputContext::Origin origin =
+      sActiveTabParent ? InputContext::ORIGIN_CONTENT : sOrigin;
+    SetIMEState(newState, nullptr, sWidget, action, origin);
   }
   sWidget = nullptr;
   sContent = nullptr;
   sPresContext = nullptr;
   sActiveTabParent = nullptr;
   return NS_OK;
 }
 
@@ -354,17 +360,19 @@ IMEStateManager::OnRemoveContent(nsPresC
 
   DestroyIMEContentObserver();
 
   // Current IME transaction should commit
   if (sWidget) {
     IMEState newState = GetNewIMEState(sPresContext, nullptr);
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::LOST_FOCUS);
-    SetIMEState(newState, nullptr, sWidget, action);
+    InputContext::Origin origin =
+      sActiveTabParent ? InputContext::ORIGIN_CONTENT : sOrigin;
+    SetIMEState(newState, nullptr, sWidget, action, origin);
   }
 
   sWidget = nullptr;
   sContent = nullptr;
   sPresContext = nullptr;
   sActiveTabParent = nullptr;
 
   return NS_OK;
@@ -508,33 +516,36 @@ IMEStateManager::OnChangeFocusInternal(n
       //     to be restored by the child process asynchronously.  Therefore,
       //     some key events which are fired immediately after closing menu
       //     may not be handled by IME.
       Unused << newTabParent->
         SendMenuKeyboardListenerInstalled(sInstalledMenuKeyboardListener);
       setIMEState = sInstalledMenuKeyboardListener;
     } else if (focusActuallyChanging) {
       InputContext context = newWidget->GetInputContext();
-      if (context.mIMEState.mEnabled == IMEState::DISABLED) {
+      if (context.mIMEState.mEnabled == IMEState::DISABLED &&
+          context.mOrigin == InputContext::ORIGIN_CONTENT) {
         setIMEState = false;
         MOZ_LOG(sISMLog, LogLevel::Debug,
           ("  OnChangeFocusInternal(), doesn't set IME "
            "state because focused element (or document) is in a child process "
-           "and the IME state is already disabled"));
+           "and the IME state is already disabled by a remote process"));
       } else {
         MOZ_LOG(sISMLog, LogLevel::Debug,
           ("  OnChangeFocusInternal(), will disable IME "
            "until new focused element (or document) in the child process "
            "will get focus actually"));
       }
-    } else {
-      // When focus is NOT changed actually, we shouldn't set IME state since
-      // that means that the window is being activated and the child process
-      // may have composition.  Then, we shouldn't commit the composition with
-      // making IME state disabled.
+    } else if (newWidget->GetInputContext().mOrigin !=
+                 InputContext::ORIGIN_CONTENT) {
+      // When focus is NOT changed actually, we shouldn't set IME state if
+      // current input context was set by a remote process since that means
+      // that the window is being activated and the child process may have
+      // composition.  Then, we shouldn't commit the composition with making
+      // IME state disabled.
       setIMEState = false;
       MOZ_LOG(sISMLog, LogLevel::Debug,
         ("  OnChangeFocusInternal(), doesn't set IME "
          "state because focused element (or document) is already in the child "
          "process"));
     }
   }
 
@@ -561,17 +572,18 @@ IMEStateManager::OnChangeFocusInternal(n
       // focus.
       bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
       aAction.mFocusChange =
         gotFocus ? InputContextAction::GOT_FOCUS :
                    InputContextAction::LOST_FOCUS;
     }
 
     // Update IME state for new focus widget
-    SetIMEState(newState, aContent, newWidget, aAction);
+    SetIMEState(newState, aContent, newWidget, aAction,
+                newTabParent ? InputContext::ORIGIN_CONTENT : sOrigin);
   }
 
   sActiveTabParent = newTabParent;
   sPresContext = aPresContext;
   sContent = aContent;
 
   // Don't call CreateIMEContentObserver() here except when a plugin gets
   // focus because it will be called from the focus event handler of focused
@@ -712,17 +724,17 @@ IMEStateManager::OnClickInEditor(nsPresC
   }
 
   InputContextAction::Cause cause =
     aMouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH ?
       InputContextAction::CAUSE_TOUCH : InputContextAction::CAUSE_MOUSE;
 
   InputContextAction action(cause, InputContextAction::FOCUS_NOT_CHANGED);
   IMEState newState = GetNewIMEState(aPresContext, aContent);
-  SetIMEState(newState, aContent, widget, action);
+  SetIMEState(newState, aContent, widget, action, sOrigin);
 }
 
 // static
 void
 IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
                                  nsIContent* aContent,
                                  EditorBase& aEditorBase)
 {
@@ -921,17 +933,17 @@ IMEStateManager::UpdateIMEState(const IM
 
   if (createTextStateManager) {
     DestroyIMEContentObserver();
   }
 
   if (updateIMEState) {
     InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                               InputContextAction::FOCUS_NOT_CHANGED);
-    SetIMEState(aNewIMEState, aContent, widget, action);
+    SetIMEState(aNewIMEState, aContent, widget, action, sOrigin);
     if (NS_WARN_IF(widget->Destroyed())) {
       MOZ_LOG(sISMLog, LogLevel::Error,
         ("  UpdateIMEState(), widget has gone during setting input context"));
       return;
     }
   }
 
   if (createTextStateManager) {
@@ -1081,32 +1093,35 @@ IMEStateManager::SetInputContextForChild
   SetInputContext(widget, aInputContext, aAction);
 }
 
 // static
 void
 IMEStateManager::SetIMEState(const IMEState& aState,
                              nsIContent* aContent,
                              nsIWidget* aWidget,
-                             InputContextAction aAction)
+                             InputContextAction aAction,
+                             InputContext::Origin aOrigin)
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
      "aContent=0x%p (TabParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
-     "mFocusChange=%s })",
+     "mFocusChange=%s }, aOrigin=%s)",
      GetIMEStateEnabledName(aState.mEnabled),
      GetIMEStateSetOpenName(aState.mOpen), aContent,
      TabParent::GetFrom(aContent), aWidget,
      GetActionCauseName(aAction.mCause),
-     GetActionFocusChangeName(aAction.mFocusChange)));
+     GetActionFocusChangeName(aAction.mFocusChange),
+     ToChar(aOrigin)));
 
   NS_ENSURE_TRUE_VOID(aWidget);
 
   InputContext context;
   context.mIMEState = aState;
+  context.mOrigin = aOrigin;
   context.mMayBeIMEUnaware = context.mIMEState.IsEditable() &&
     sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent);
 
   if (aContent &&
       aContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) {
     if (!aContent->IsHTMLElement(nsGkAtoms::textarea)) {
       // <input type=number> has an anonymous <input type=text> descendant
       // that gets focus whenever anyone tries to focus the number control. We
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -243,17 +243,18 @@ public:
 
 protected:
   static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
                                         nsIContent* aContent,
                                         InputContextAction aAction);
   static void SetIMEState(const IMEState &aState,
                           nsIContent* aContent,
                           nsIWidget* aWidget,
-                          InputContextAction aAction);
+                          InputContextAction aAction,
+                          InputContext::Origin aOrigin);
   static void SetInputContext(nsIWidget* aWidget,
                               const InputContext& aInputContext,
                               const InputContextAction& aAction);
   static IMEState GetNewIMEState(nsPresContext* aPresContext,
                                  nsIContent* aContent);
 
   static void EnsureTextCompositionArray();
   static void CreateIMEContentObserver(EditorBase* aEditorBase);
@@ -295,16 +296,19 @@ protected:
   static StaticRefPtr<IMEContentObserver> sActiveIMEContentObserver;
 
   // All active compositions in the process are stored by this array.
   // When you get an item of this array and use it, please be careful.
   // The instances in this array can be destroyed automatically if you do
   // something to cause committing or canceling the composition.
   static TextCompositionArray* sTextCompositions;
 
+  // Origin type of current process.
+  static InputContext::Origin sOrigin;
+
   static bool           sInstalledMenuKeyboardListener;
   static bool           sIsGettingNewIMEState;
   static bool           sCheckForIMEUnawareWebApps;
   static bool           sInputModeSupported;
   static bool           sRemoteHasFocus;
 
   class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
   {
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -322,16 +322,19 @@ struct InputContext final
   {
     if (XRE_IsParentProcess()) {
       return IsOriginMainProcess();
     }
     return IsOriginContentProcess();
   }
 };
 
+// FYI: Implemented in nsBaseWidget.cpp
+const char* ToChar(InputContext::Origin aOrigin);
+
 struct InputContextAction final
 {
   /**
    * mCause indicates what action causes calling nsIWidget::SetInputContext().
    * It must be one of following values.
    */
   enum Cause
   {
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -2323,16 +2323,29 @@ nsIWidget::GetEditCommands(nsIWidget::Na
   MOZ_ASSERT(aEvent.IsTrusted());
   MOZ_ASSERT(aCommands.IsEmpty());
 }
 
 namespace mozilla {
 namespace widget {
 
 const char*
+ToChar(InputContext::Origin aOrigin)
+{
+  switch (aOrigin) {
+    case InputContext::ORIGIN_MAIN:
+      return "ORIGIN_MAIN";
+    case InputContext::ORIGIN_CONTENT:
+      return "ORIGIN_CONTENT";
+    default:
+      return "Unexpected value";
+  }
+}
+
+const char*
 ToChar(IMEMessage aIMEMessage)
 {
   switch (aIMEMessage) {
     case NOTIFY_IME_OF_NOTHING:
       return "NOTIFY_IME_OF_NOTHING";
     case NOTIFY_IME_OF_FOCUS:
       return "NOTIFY_IME_OF_FOCUS";
     case NOTIFY_IME_OF_BLUR: