Bug 1367692 - Make IMEHandler not restore default IMC unless legacy IMM-IME is active. r=m_kato, a=gchang FIREFOX_BETA_54_END
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 07 Jun 2017 11:42:27 +0900
changeset 592612 d8424bcbf72f7a451e89f8f625a9ebafecded872
parent 592611 4e43d1eed998cb835c19030efbf314f6602a8c1c
child 592614 d0fa55d83a4217327350bf5e5dd0232333526a7d
child 595783 fbca11c089a042348cb4c7d9dc287563b8bb84aa
push id63442
push userCallek@gmail.com
push dateMon, 12 Jun 2017 14:13:53 +0000
reviewersm_kato, gchang
bugs1367692
milestone54.0
Bug 1367692 - Make IMEHandler not restore default IMC unless legacy IMM-IME is active. r=m_kato, a=gchang TIPs (and normal keyboard layouts) don't need IMC on focused window. So, in most environment, it's not necessary to restore default IMC of focused window. Therefore, this patch makes IMEHandler not restore default IMC unless legacy IMM-IME is active and disassociate IMC from focused window when IMM-IME isn't active. However, this is risky change. Therefore, the new behavior is disabled in default settings. On the other hand, we need the new behavior only when MS-IME for Japanese is active on Win10. Therefore, this patch adds a pref to enable/disable the hack and make it true in the default settings. MozReview-Commit-ID: KAVxVT9CrsW
modules/libpref/init/all.js
widget/windows/IMMHandler.cpp
widget/windows/IMMHandler.h
widget/windows/TSFTextStore.cpp
widget/windows/TSFTextStore.h
widget/windows/WinIMEHandler.cpp
widget/windows/WinIMEHandler.h
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3513,16 +3513,21 @@ pref("intl.keyboard.per_window_layout", 
 
 #ifdef NS_ENABLE_TSF
 // Enable/Disable TSF support on Vista or later.
 pref("intl.tsf.enable", true);
 
 // Support IMEs implemented with IMM in TSF mode.
 pref("intl.tsf.support_imm", true);
 
+// This is referred only when both "intl.tsf.enable" and "intl.tsf.support_imm"
+// are true.  When this is true, default IMC is associated with focused window
+// only when active keyboard layout is a legacy IMM-IME.
+pref("intl.tsf.associate_imc_only_when_imm_ime_is_active", false);
+
 // Enables/Disables hack for specific TIP.
 
 // Whether creates native caret for ATOK or not.
 pref("intl.tsf.hack.atok.create_native_caret", true);
 // Whether use available composition string rect for result of
 // ITfContextView::GetTextExt() even if the specified range is same as the
 // range of composition string but some character rects of them are not
 // available.  Note that this is ignored if active ATOK is or older than 2016
@@ -3538,16 +3543,21 @@ pref("intl.tsf.hack.ms_simplified_chines
 // For Microsoft ChangJie and Microsoft Quick
 pref("intl.tsf.hack.ms_traditional_chinese.do_not_return_no_layout_error", true);
 // For Easy Changjei
 pref("intl.tsf.hack.easy_changjei.do_not_return_no_layout_error", true);
 // Whether use previous character rect for the result of
 // ITfContextView::GetTextExt() if the specified range is the first character
 // of selected clause of composition string.
 pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_first_char", true);
+// Whether default IMC should be associated with focused window when MS-IME
+// for Japanese on Win10 is active.  MS-IME for Japanese on Win10 has a crash
+// bug.  While restoring default IMC when MS-IME for Japanese is active,
+// it sometimes crashes after Creators Update.  This pref avoid the crash.
+pref("intl.tsf.hack.ms_japanese_ime.do_not_associate_imc_on_win10", true);
 // Whether use previous character rect for the result of
 // ITfContextView::GetTextExt() if the specified range is the caret of
 // composition string.
 pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_caret", true);
 // Whether hack ITextStoreACP::QueryInsert() or not.  The method should return
 // new selection after specified length text is inserted at specified range.
 // However, Microsoft's some Chinese TIPs expect that the result is same as
 // specified range.  If following prefs are true, ITextStoreACP::QueryInsert()
--- a/widget/windows/IMMHandler.cpp
+++ b/widget/windows/IMMHandler.cpp
@@ -175,34 +175,34 @@ LazyLogModule gIMMLog("nsIMM32HandlerWid
  ******************************************************************************/
 
 IMEContext::IMEContext(HWND aWnd)
   : mWnd(aWnd)
   , mIMC(::ImmGetContext(aWnd))
 {
 }
 
-IMEContext::IMEContext(nsWindow* aWindow)
-  : mWnd(aWindow->GetWindowHandle())
-  , mIMC(::ImmGetContext(aWindow->GetWindowHandle()))
+IMEContext::IMEContext(nsWindowBase* aWindowBase)
+  : mWnd(aWindowBase->GetWindowHandle())
+  , mIMC(::ImmGetContext(aWindowBase->GetWindowHandle()))
 {
 }
 
 void
 IMEContext::Init(HWND aWnd)
 {
   Clear();
   mWnd = aWnd;
   mIMC = ::ImmGetContext(mWnd);
 }
 
 void
-IMEContext::Init(nsWindow* aWindow)
+IMEContext::Init(nsWindowBase* aWindowBase)
 {
-  Init(aWindow->GetWindowHandle());
+  Init(aWindowBase->GetWindowHandle());
 }
 
 void
 IMEContext::Clear()
 {
   if (mWnd && mIMC) {
     ::ImmReleaseContext(mWnd, mIMC);
   }
--- a/widget/windows/IMMHandler.h
+++ b/widget/windows/IMMHandler.h
@@ -14,46 +14,47 @@
 #include "nsIWidget.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/TextEventDispatcher.h"
 #include "nsRect.h"
 #include "WritingModes.h"
 #include "npapi.h"
 
 class nsWindow;
+class nsWindowBase;
 
 namespace mozilla {
 namespace widget {
 
 struct MSGResult;
 
 class IMEContext final
 {
 public:
   IMEContext()
     : mWnd(nullptr)
     , mIMC(nullptr)
   {
   }
 
   explicit IMEContext(HWND aWnd);
-  explicit IMEContext(nsWindow* aWindow);
+  explicit IMEContext(nsWindowBase* aWindowBase);
 
   ~IMEContext()
   {
     Clear();
   }
 
   HIMC get() const
   {
     return mIMC;
   }
 
   void Init(HWND aWnd);
-  void Init(nsWindow* aWindow);
+  void Init(nsWindowBase* aWindowBase);
   void Clear();
 
   bool IsValid() const
   {
     return !!mIMC;
   }
 
   void SetOpenState(bool aOpen) const
--- a/widget/windows/TSFTextStore.cpp
+++ b/widget/windows/TSFTextStore.cpp
@@ -1,33 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#define INPUTSCOPE_INIT_GUID
+#define TEXTATTRS_INIT_GUID
+#include "TSFTextStore.h"
+
 #include <olectl.h>
 #include <algorithm>
 
-#include "mozilla/Logging.h"
-
 #include "nscore.h"
 #include "nsWindow.h"
 #include "nsPrintfCString.h"
+#include "WinIMEHandler.h"
 #include "WinUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEventDispatcher.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsIXULRuntime.h"
 
-#define INPUTSCOPE_INIT_GUID
-#define TEXTATTRS_INIT_GUID
-#include "TSFTextStore.h"
-
 namespace mozilla {
 namespace widget {
 
 static const char* kPrefNameEnableTSF = "intl.tsf.enable";
 
 /**
  * TSF related code should log its behavior even on release build especially
  * in the interface methods.
@@ -1032,17 +1032,17 @@ public:
 
   NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFStaticSink)
 
   const nsString& GetActiveTIPKeyboardDescription() const
   {
     return mActiveTIPKeyboardDescription;
   }
 
-  static bool IsIMM_IME()
+  static bool IsIMM_IMEActive()
   {
     if (!sInstance || !sInstance->EnsureInitActiveTIPKeyboard()) {
       return IsIMM_IME(::GetKeyboardLayout(0));
     }
     return sInstance->mIsIMM_IME;
   }
 
   static bool IsIMM_IME(HKL aHKL)
@@ -1350,16 +1350,18 @@ TSFStaticSink::OnActivated(DWORD dwProfi
       (dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ||
        catid == GUID_TFCAT_TIP_KEYBOARD)) {
     mOnActivatedCalled = true;
     mActiveTIPGUID = guidProfile;
     mLangID = langid;
     mIsIMM_IME = IsIMM_IME(hkl);
     GetTIPDescription(rclsid, mLangID, guidProfile,
                       mActiveTIPKeyboardDescription);
+    // Notify IMEHandler of changing active keyboard layout.
+    IMEHandler::OnKeyboardLayoutChanged();
   }
   MOZ_LOG(sTextStoreLog, LogLevel::Info,
     ("0x%p TSFStaticSink::OnActivated(dwProfileType=%s (0x%08X), "
      "langid=0x%08X, rclsid=%s, catid=%s, guidProfile=%s, hkl=0x%08X, "
      "dwFlags=0x%08X (TF_IPSINK_FLAG_ACTIVE: %s)), mIsIMM_IME=%s, "
      "mActiveTIPDescription=\"%s\"",
      this, dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR ?
              "TF_PROFILETYPE_INPUTPROCESSOR" :
@@ -6284,19 +6286,26 @@ TSFTextStore::ProcessMessage(nsWindowBas
       }
       break;
     }
   }
 }
 
 // static
 bool
-TSFTextStore::IsIMM_IME()
+TSFTextStore::IsIMM_IMEActive()
 {
-  return TSFStaticSink::IsIMM_IME();
+  return TSFStaticSink::IsIMM_IMEActive();
+}
+
+// static
+bool
+TSFTextStore::IsMSJapaneseIMEActive()
+{
+  return TSFStaticSink::GetInstance()->IsMSJapaneseIMEActive();
 }
 
 /******************************************************************/
 /* TSFTextStore::Composition                                       */
 /******************************************************************/
 
 void
 TSFTextStore::Composition::Start(ITfCompositionView* aCompositionView,
--- a/widget/windows/TSFTextStore.h
+++ b/widget/windows/TSFTextStore.h
@@ -1,23 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TSFTextStore_h_
 #define TSFTextStore_h_
 
-#include "mozilla/RefPtr.h"
-#include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIWidget.h"
+#include "nsString.h"
 #include "nsWindowBase.h"
+
 #include "WinUtils.h"
+#include "WritingModes.h"
+
 #include "mozilla/Attributes.h"
+#include "mozilla/RefPtr.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextEventDispatcher.h"
 #include "mozilla/TextRange.h"
 #include "mozilla/WindowsVersion.h"
 
 #include <msctf.h>
 #include <textstor.h>
 
@@ -230,17 +233,30 @@ public:
     return (sEnabledTextStore && sEnabledTextStore->mComposition.IsComposing());
   }
 
   static bool IsComposingOn(nsWindowBase* aWidget)
   {
     return (IsComposing() && sEnabledTextStore->mWidget == aWidget);
   }
 
-  static bool IsIMM_IME();
+  static nsWindowBase* GetEnabledWindowBase()
+  {
+    return sEnabledTextStore ? sEnabledTextStore->mWidget.get() : nullptr;
+  }
+
+  /**
+   * Returns true if active keyboard layout is a legacy IMM-IME.
+   */
+  static bool IsIMM_IMEActive();
+
+  /**
+   * Returns true if active TIP is MS-IME for Japanese.
+   */
+  static bool IsMSJapaneseIMEActive();
 
 #ifdef DEBUG
   // Returns true when keyboard layout has IME (TIP).
   static bool     CurrentKeyboardLayoutHasIME();
 #endif // #ifdef DEBUG
 
 protected:
   TSFTextStore();
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WinIMEHandler.h"
 
 #include "IMMHandler.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/WindowsVersion.h"
 #include "nsWindowDefs.h"
 #include "WinTextEventDispatcherListener.h"
 
 #ifdef NS_ENABLE_TSF
 #include "TSFTextStore.h"
 #endif // #ifdef NS_ENABLE_TSF
 
 #include "nsLookAndFeel.h"
@@ -42,31 +43,36 @@ namespace widget {
 nsWindow* IMEHandler::sFocusedWindow = nullptr;
 InputContextAction::Cause IMEHandler::sLastContextActionCause =
   InputContextAction::CAUSE_UNKNOWN;
 bool IMEHandler::sPluginHasFocus = false;
 
 #ifdef NS_ENABLE_TSF
 bool IMEHandler::sIsInTSFMode = false;
 bool IMEHandler::sIsIMMEnabled = true;
+bool IMEHandler::sAssociateIMCOnlyWhenIMM_IMEActive = false;
 decltype(SetInputScopes)* IMEHandler::sSetInputScopes = nullptr;
 #endif // #ifdef NS_ENABLE_TSF
 
 static POWER_PLATFORM_ROLE sPowerPlatformRole = PlatformRoleUnspecified;
 static bool sDeterminedPowerPlatformRole = false;
 
 // static
 void
 IMEHandler::Initialize()
 {
 #ifdef NS_ENABLE_TSF
   TSFTextStore::Initialize();
   sIsInTSFMode = TSFTextStore::IsInTSFMode();
   sIsIMMEnabled =
     !sIsInTSFMode || Preferences::GetBool("intl.tsf.support_imm", true);
+  sAssociateIMCOnlyWhenIMM_IMEActive =
+    sIsIMMEnabled &&
+    Preferences::GetBool("intl.tsf.associate_imc_only_when_imm_ime_is_active",
+                         false);
   if (!sIsInTSFMode) {
     // When full TSFTextStore is not available, try to use SetInputScopes API
     // to enable at least InputScope. Use GET_MODULE_HANDLE_EX_FLAG_PIN to
     // ensure that msctf.dll will not be unloaded.
     HMODULE module = nullptr;
     if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, L"msctf.dll",
                            &module)) {
       sSetInputScopes = reinterpret_cast<decltype(SetInputScopes)*>(
@@ -168,33 +174,34 @@ IMEHandler::ProcessMessage(nsWindow* aWi
       return true;
     }
     // If we don't support IMM in TSF mode, we don't use IMMHandler.
     if (!sIsIMMEnabled) {
       return false;
     }
     // IME isn't implemented with IMM, IMMHandler shouldn't handle any
     // messages.
-    if (!TSFTextStore::IsIMM_IME()) {
+    if (!TSFTextStore::IsIMM_IMEActive()) {
       return false;
     }
   }
 #endif // #ifdef NS_ENABLE_TSF
 
   return IMMHandler::ProcessMessage(aWindow, aMessage, aWParam, aLParam,
                                     aResult);
 }
 
 #ifdef NS_ENABLE_TSF
 // static
 bool
 IMEHandler::IsIMMActive()
 {
-  return TSFTextStore::IsIMM_IME();
+  return TSFTextStore::IsIMM_IMEActive();
 }
+
 #endif // #ifdef NS_ENABLE_TSF
 
 // static
 bool
 IMEHandler::IsComposing()
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
@@ -403,16 +410,37 @@ IMEHandler::OnDestroyWindow(nsWindow* aW
     // MSDN says we need to set IS_DEFAULT to avoid memory leak when we use
     // SetInputScopes API. Use an empty string to do this.
     SetInputScopeForIMM32(aWindow, EmptyString(), EmptyString());
   }
 #endif // #ifdef NS_ENABLE_TSF
   AssociateIMEContext(aWindow, true);
 }
 
+#ifdef NS_ENABLE_TSF
+// static
+bool
+IMEHandler::NeedsToAssociateIMC()
+{
+  if (sAssociateIMCOnlyWhenIMM_IMEActive) {
+    return TSFTextStore::IsIMM_IMEActive();
+  }
+
+  // Even if IMC should be associated with focused widget with non-IMM-IME,
+  // we need to avoid crash bug of MS-IME for Japanese on Win10.  It crashes
+  // while we're associating default IME to a window when it's active.
+  static const bool sDoNotAssociateIMCWhenMSJapaneseIMEActiveOnWin10 =
+    IsWin10OrLater() &&
+    Preferences::GetBool(
+      "intl.tsf.hack.ms_japanese_ime.do_not_associate_imc_on_win10", true);
+  return !sDoNotAssociateIMCWhenMSJapaneseIMEActiveOnWin10 ||
+         !TSFTextStore::IsMSJapaneseIMEActive();
+}
+#endif // #ifdef NS_ENABLE_TSF
+
 // static
 void
 IMEHandler::SetInputContext(nsWindow* aWindow,
                             InputContext& aInputContext,
                             const InputContextAction& aAction)
 {
   sLastContextActionCause = aAction.mCause;
   // FYI: If there is no composition, this call will do nothing.
@@ -434,18 +462,18 @@ IMEHandler::SetInputContext(nsWindow* aW
     aInputContext.mIMEState.mOpen == IMEState::OPEN);
 
 #ifdef NS_ENABLE_TSF
   // Note that even while a plugin has focus, we need to notify TSF of that.
   if (sIsInTSFMode) {
     TSFTextStore::SetInputContext(aWindow, aInputContext, aAction);
     if (IsTSFAvailable()) {
       if (sIsIMMEnabled) {
-        // Associate IME context for IMM-IMEs.
-        AssociateIMEContext(aWindow, enable);
+        // Associate IMC with aWindow only when it's necessary.
+        AssociateIMEContext(aWindow, enable && NeedsToAssociateIMC());
       } else if (oldInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
         // Disassociate the IME context from the window when plugin loses focus
         // in pure TSF mode.
         AssociateIMEContext(aWindow, false);
       }
       if (adjustOpenState) {
         TSFTextStore::SetIMEOpenState(open);
       }
@@ -463,25 +491,25 @@ IMEHandler::SetInputContext(nsWindow* aW
   IMEContext context(aWindow);
   if (adjustOpenState) {
     context.SetOpenState(open);
   }
 }
 
 // static
 void
-IMEHandler::AssociateIMEContext(nsWindow* aWindow, bool aEnable)
+IMEHandler::AssociateIMEContext(nsWindowBase* aWindowBase, bool aEnable)
 {
-  IMEContext context(aWindow);
+  IMEContext context(aWindowBase);
   if (aEnable) {
     context.AssociateDefaultContext();
     return;
   }
   // Don't disassociate the context after the window is destroyed.
-  if (aWindow->Destroyed()) {
+  if (aWindowBase->Destroyed()) {
     return;
   }
   context.Disassociate();
 }
 
 // static
 void
 IMEHandler::InitInputContext(nsWindow* aWindow, InputContext& aInputContext)
@@ -521,16 +549,43 @@ IMEHandler::CurrentKeyboardLayoutHasIME(
 #endif // #ifdef NS_ENABLE_TSF
 
   return IMMHandler::IsIMEAvailable();
 }
 #endif // #ifdef DEBUG
 
 // static
 void
+IMEHandler::OnKeyboardLayoutChanged()
+{
+  if (!sIsIMMEnabled || !IsTSFAvailable()) {
+    return;
+  }
+
+  // If there is no TSFTextStore which has focus, i.e., no editor has focus,
+  // nothing to do here.
+  nsWindowBase* windowBase = TSFTextStore::GetEnabledWindowBase();
+  if (!windowBase) {
+    return;
+  }
+
+  // If IME isn't available, nothing to do here.
+  InputContext inputContext = windowBase->GetInputContext();
+  if (!WinUtils::IsIMEEnabled(inputContext)) {
+    return;
+  }
+
+  // Associate or Disassociate IMC if it's necessary.
+  // Note that this does nothing if the window has already associated with or
+  // disassociated from the window.
+  AssociateIMEContext(windowBase, NeedsToAssociateIMC());
+}
+
+// static
+void
 IMEHandler::SetInputScopeForIMM32(nsWindow* aWindow,
                                   const nsAString& aHTMLInputType,
                                   const nsAString& aHTMLInputInputmode)
 {
   if (sIsInTSFMode || !sSetInputScopes || aWindow->Destroyed()) {
     return;
   }
   UINT arraySize = 0;
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WinIMEHandler_h_
 #define WinIMEHandler_h_
 
 #include "nscore.h"
-#include "nsIWidget.h"
+#include "nsWindowBase.h"
 #include "npapi.h"
 #include <windows.h>
 #include <inputscope.h>
 
 #define NS_WM_IMEFIRST WM_IME_SETCONTEXT
 #define NS_WM_IMELAST  WM_IME_KEYUP
 
 class nsWindow;
@@ -95,19 +95,19 @@ public:
    * Called when nsIWidget::SetInputContext() is called before the window's
    * InputContext is modified actually.
    */
   static void SetInputContext(nsWindow* aWindow,
                               InputContext& aInputContext,
                               const InputContextAction& aAction);
 
   /**
-   * Associate or disassociate IME context to/from the aWindow.
+   * Associate or disassociate IME context to/from the aWindowBase.
    */
-  static void AssociateIMEContext(nsWindow* aWindow, bool aEnable);
+  static void AssociateIMEContext(nsWindowBase* aWindowBase, bool aEnable);
 
   /**
    * Called when the window is created.
    */
   static void InitInputContext(nsWindow* aWindow, InputContext& aInputContext);
 
   /*
    * For windowless plugin helper.
@@ -115,16 +115,23 @@ public:
   static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
 
   /*
    * For WM_IME_*COMPOSITION messages and e10s with windowless plugin
    */
   static void DefaultProcOfPluginEvent(nsWindow* aWindow,
                                        const NPEvent* aPluginEvent);
 
+#ifdef NS_ENABLE_TSF
+  /**
+   * This is called by TSFStaticSink when active IME is changed.
+   */
+  static void OnKeyboardLayoutChanged();
+#endif // #ifdef NS_ENABLE_TSF
+
 #ifdef DEBUG
   /**
    * Returns true when current keyboard layout has IME.  Otherwise, false.
    */
   static bool CurrentKeyboardLayoutHasIME();
 #endif // #ifdef DEBUG
 
 private:
@@ -137,28 +144,30 @@ private:
   static decltype(SetInputScopes)* sSetInputScopes;
   static void SetInputScopeForIMM32(nsWindow* aWindow,
                                     const nsAString& aHTMLInputType,
                                     const nsAString& aHTMLInputInputmode);
   static bool sIsInTSFMode;
   // If sIMMEnabled is false, any IME messages are not handled in TSF mode.
   // Additionally, IME context is always disassociated from focused window.
   static bool sIsIMMEnabled;
+  static bool sAssociateIMCOnlyWhenIMM_IMEActive;
 
   static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
   static bool IsIMMActive();
 
   static void MaybeShowOnScreenKeyboard();
   static void MaybeDismissOnScreenKeyboard(nsWindow* aWindow);
   static bool WStringStartsWithCaseInsensitive(const std::wstring& aHaystack,
                                                const std::wstring& aNeedle);
   static bool NeedOnScreenKeyboard();
   static bool IsKeyboardPresentOnSlate();
   static bool IsInTabletMode();
   static bool AutoInvokeOnScreenKeyboardInDesktopMode();
+  static bool NeedsToAssociateIMC();
 
   /**
    * Show the Windows on-screen keyboard. Only allowed for
    * chrome documents and Windows 8 and higher.
    */
   static void ShowOnScreenKeyboard();
 
   /**