Bug 1179632 part.1 native IME context should not be stored in InputContext but should be able to retrieve with nsIWidget::GetNativeData() r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 11 Dec 2015 15:15:57 +0900
changeset 310306 a58871d438cc47cc9e5b835b969ca27084cbbae4
parent 310305 c873567c28985beea81409a53508ec804dc6ba05
child 310307 63101b99fa95195574c9eab5680b1f1acd4442ba
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1179632
milestone45.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 1179632 part.1 native IME context should not be stored in InputContext but should be able to retrieve with nsIWidget::GetNativeData() r=smaug
dom/events/TextComposition.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/IMEData.h
widget/PuppetWidget.cpp
widget/android/nsWindow.cpp
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/gonk/nsWindow.cpp
widget/gtk/nsWindow.cpp
widget/nsIWidget.h
widget/qt/nsWindow.cpp
widget/uikit/nsWindow.mm
widget/windows/IMMHandler.cpp
widget/windows/IMMHandler.h
widget/windows/WinIMEHandler.cpp
widget/windows/WinIMEHandler.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -35,17 +35,17 @@ bool TextComposition::sHandlingSelection
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
                                  TabParent* aTabParent,
                                  WidgetCompositionEvent* aCompositionEvent)
   : mPresContext(aPresContext)
   , mNode(aNode)
   , mTabParent(aTabParent)
   , mNativeContext(
-      aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
+      aCompositionEvent->widget->GetNativeData(NS_NATIVE_IME_CONTEXT))
   , mCompositionStartOffset(0)
   , mCompositionTargetOffset(0)
   , mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
   , mIsComposing(false)
   , mIsEditorHandlingEvent(false)
   , mIsRequestingCommit(false)
   , mIsRequestingCancel(false)
   , mRequestedToCommitOrCancel(false)
@@ -64,17 +64,17 @@ TextComposition::Destroy()
   mTabParent = nullptr;
   // TODO: If the editor is still alive and this is held by it, we should tell
   //       this being destroyed for cleaning up the stuff.
 }
 
 bool
 TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
 {
-  return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
+  return mNativeContext == aWidget->GetNativeData(NS_NATIVE_IME_CONTEXT);
 }
 
 bool
 TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const
 {
   return !Destroyed() && aWidget && !aWidget->Destroyed() &&
          mPresContext->GetPresShell() &&
          !mPresContext->GetPresShell()->IsDestroying();
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -291,18 +291,17 @@ parent:
      * Indicate, based on the current state, that some commands are enabled and
      * some are disabled.
      */
     EnableDisableCommands(nsString action,
                           nsCString[] enabledCommands,
                           nsCString[] disabledCommands);
 
     prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
-                                                 int32_t IMEOpen,
-                                                 intptr_t NativeIMEContext);
+                                                 int32_t IMEOpen);
 
     prio(urgent) async SetInputContext(int32_t IMEEnabled,
                                        int32_t IMEOpen,
                                        nsString type,
                                        nsString inputmode,
                                        nsString actionHint,
                                        int32_t cause,
                                        int32_t focusChange);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2358,31 +2358,28 @@ TabParent::RecvSetPluginFocused(const bo
     return true;
   }
   widget->SetPluginFocused((bool&)aFocused);
   return true;
 }
 
 bool
 TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
-                               int32_t* aIMEOpen,
-                               intptr_t* aNativeIMEContext)
+                               int32_t* aIMEOpen)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aIMEEnabled = IMEState::DISABLED;
     *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    *aNativeIMEContext = 0;
     return true;
   }
 
   InputContext context = widget->GetInputContext();
   *aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
   *aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
-  *aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
   return true;
 }
 
 bool
 TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
                                const int32_t& aIMEOpen,
                                const nsString& aType,
                                const nsString& aInputmode,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -191,18 +191,17 @@ public:
                                        bool* aNoCompositionEvent,
                                        nsString* aComposition) override;
     virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
                                     const int32_t& aPanelX,
                                     const int32_t& aPanelY,
                                     nsString* aCommitted) override;
     virtual bool RecvSetPluginFocused(const bool& aFocused) override;
     virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
-                                     int32_t* aIMEOpen,
-                                     intptr_t* aNativeIMEContext) override;
+                                     int32_t* aIMEOpen) override;
     virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
                                      const int32_t& aIMEOpen,
                                      const nsString& aType,
                                      const nsString& aInputmode,
                                      const nsString& aActionHint,
                                      const int32_t& aCause,
                                      const int32_t& aFocusChange) override;
     virtual bool RecvRequestFocus(const bool& aCanRaise) override;
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -218,21 +218,25 @@ struct IMEState final
   // a plain text editor whose ime-mode is "disabled" or a windowless plugin
   // has focus.
   bool MaybeEditable() const
   {
     return IsEditable() || mEnabled == PLUGIN;
   }
 };
 
+// NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
+// If there can be only one IME composition in a process, this can be used.
+#define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
+  (reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
+
 struct InputContext final
 {
   InputContext()
-    : mNativeIMEContext(nullptr)
-    , mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
+    : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
     , mMayBeIMEUnaware(false)
   {
   }
 
   bool IsPasswordEditor() const
   {
     return mHTMLInputType.LowerCaseEqualsLiteral("password");
   }
@@ -243,21 +247,16 @@ struct InputContext final
   nsString mHTMLInputType;
 
   /* The type of the inputmode */
   nsString mHTMLInputInputmode;
 
   /* A hint for the action that is performed when the input is submitted */
   nsString mActionHint;
 
-  /* Native IME context for the widget.  This doesn't come from the argument of
-     SetInputContext().  If there is only one context in the process, this may
-     be nullptr. */
-  void* mNativeIMEContext;
-
   /**
    * mOrigin indicates whether this focus event refers to main or remote
    * content.
    */
   enum Origin
   {
     // Adjusting focus of content on the main process
     ORIGIN_MAIN,
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -670,21 +670,20 @@ PuppetWidget::GetInputContext()
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return InputContext();
 #endif
 
   InputContext context;
   if (mTabChild) {
     int32_t enabled, open;
-    intptr_t nativeIMEContext;
-    mTabChild->SendGetInputContext(&enabled, &open, &nativeIMEContext);
+    // TODO: This is too expensive. PuppetWidget should cache IMEState.
+    mTabChild->SendGetInputContext(&enabled, &open);
     context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
     context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
-    context.mNativeIMEContext = reinterpret_cast<void*>(nativeIMEContext);
   }
   return context;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
@@ -1116,16 +1115,19 @@ PuppetWidget::GetNativeData(uint32_t aDa
       mTabChild->SendGetWidgetNativeData(&nativeData);
     }
     return (void*)nativeData;
   }
   case NS_NATIVE_WIDGET:
   case NS_NATIVE_DISPLAY:
     // These types are ignored (see bug 1183828).
     break;
+  case NS_NATIVE_IME_CONTEXT:
+    // TODO: Implement this in next patch.
+    return nullptr;
   case NS_NATIVE_WINDOW:
   case NS_NATIVE_PLUGIN_PORT:
   case NS_NATIVE_GRAPHIC:
   case NS_NATIVE_SHELLWIDGET:
   default:
     NS_WARNING("nsWindow::GetNativeData called with bad value");
     break;
   }
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1258,16 +1258,21 @@ nsWindow::GetNativeData(uint32_t aDataTy
 {
     switch (aDataType) {
         // used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
         case NS_NATIVE_DISPLAY:
             return nullptr;
 
         case NS_NATIVE_WIDGET:
             return (void *) this;
+
+        case NS_NATIVE_IME_CONTEXT:
+            // We assume that there is only one context per process on Android
+            return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+
     }
 
     return nullptr;
 }
 
 void
 nsWindow::OnMouseEvent(AndroidGeckoEvent *ae)
 {
@@ -2239,18 +2244,16 @@ nsWindow::Natives::SetInputContext(const
     });
 }
 
 InputContext
 nsWindow::Natives::GetInputContext()
 {
     InputContext context = mInputContext;
     context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    // We assume that there is only one context per process on Android
-    context.mNativeIMEContext = nullptr;
     return context;
 }
 
 void
 nsWindow::Natives::OnImeSynchronize()
 {
     if (!mIMEMaskEventsCount) {
         FlushIMEChanges();
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -679,16 +679,27 @@ void* nsChildView::GetNativeData(uint32_
 
     case NS_NATIVE_OFFSETX:
       retVal = 0;
       break;
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
+
+    case NS_NATIVE_IME_CONTEXT:
+      retVal = [mView inputContext];
+      // If input context isn't available on this widget, we should set |this|
+      // instead of nullptr since if this returns nullptr, IMEStateManager
+      // cannot manage composition with TextComposition instance.  Although,
+      // this case shouldn't occur.
+      if (NS_WARN_IF(!retVal)) {
+        retVal = this;
+      }
+      break;
   }
 
   return retVal;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
 }
 
 #pragma mark -
@@ -1764,23 +1775,16 @@ nsChildView::GetInputContext()
         break;
       }
       // If mTextInputHandler is null, set CLOSED instead...
       MOZ_FALLTHROUGH;
     default:
       mInputContext.mIMEState.mOpen = IMEState::CLOSED;
       break;
   }
-  mInputContext.mNativeIMEContext = [mView inputContext];
-  // If input context isn't available on this widget, we should set |this|
-  // instead of nullptr since nullptr means that the platform has only one
-  // context per process.
-  if (!mInputContext.mNativeIMEContext) {
-    mInputContext.mNativeIMEContext = this;
-  }
   return mInputContext;
 }
 
 NS_IMETHODIMP
 nsChildView::AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
   return mTextInputHandler->AttachNativeKeyEvent(aEvent);
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -360,26 +360,16 @@ public:
     void SetMenuBar(nsMenuBarX* aMenuBar);
     nsMenuBarX *GetMenuBar();
 
     NS_IMETHOD_(void) SetInputContext(
                         const InputContext& aContext,
                         const InputContextAction& aAction) override;
     NS_IMETHOD_(InputContext) GetInputContext() override
     {
-      NSView* view = mWindow ? [mWindow contentView] : nil;
-      if (view) {
-        mInputContext.mNativeIMEContext = [view inputContext];
-      }
-      // If inputContext isn't available on this window, returns this window's
-      // pointer since nullptr means the platform has only one context per
-      // process.
-      if (!mInputContext.mNativeIMEContext) {
-        mInputContext.mNativeIMEContext = this;
-      }
       return mInputContext;
     }
     NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
                         NativeKeyBindingsType aType,
                         const mozilla::WidgetKeyboardEvent& aEvent,
                         DoCommandCallback aCallback,
                         void* aCallbackData) override;
 
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -587,16 +587,30 @@ void* nsCocoaWindow::GetNativeData(uint3
       retVal = mWindow;
       break;
       
     case NS_NATIVE_GRAPHIC:
       // There isn't anything that makes sense to return here,
       // and it doesn't matter so just return nullptr.
       NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a top-level window!");
       break;
+    case NS_NATIVE_IME_CONTEXT: {
+      NSView* view = mWindow ? [mWindow contentView] : nil;
+      if (view) {
+        retVal = [view inputContext];
+      }
+      // If inputContext isn't available on this window, return this window's
+      // pointer instead of nullptr since if this returns nullptr,
+      // IMEStateManager cannot manage composition with TextComposition
+      // instance.  Although, this case shouldn't occur.
+      if (NS_WARN_IF(!retVal)) {
+        retVal = this;
+      }
+      break;
+    }
   }
 
   return retVal;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
 }
 
 bool nsCocoaWindow::IsVisible() const
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -534,16 +534,19 @@ void*
 nsWindow::GetNativeData(uint32_t aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
         // Called before primary display's EGLSurface creation.
         return mScreen->GetNativeWindow();
     case NS_NATIVE_OPENGL_CONTEXT:
         return mScreen->GetGLContext().take();
+    case NS_NATIVE_IME_CONTEXT:
+        // There is only one IME context on Gonk.
+        return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
     }
 
     return nullptr;
 }
 
 void
 nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
 {
@@ -577,18 +580,16 @@ nsWindow::SetInputContext(const InputCon
                           const InputContextAction& aAction)
 {
     mInputContext = aContext;
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
-    // There is only one IME context on Gonk.
-    mInputContext.mNativeIMEContext = nullptr;
     return mInputContext;
 }
 
 NS_IMETHODIMP
 nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
 {
     return NS_OK;
 }
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1732,16 +1732,25 @@ nsWindow::GetNativeData(uint32_t aDataTy
 
     case NS_NATIVE_SHELLWIDGET:
         return GetToplevelWidget();
 
     case NS_NATIVE_SHAREABLE_WINDOW:
         return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
     case NS_NATIVE_PLUGIN_OBJECT_PTR:
         return (void *) mPluginNativeWindow;
+    case NS_NATIVE_IME_CONTEXT:
+        // If IME context isn't available on this widget, we should set |this|
+        // instead of nullptr since if we return nullptr, IMEStateManager
+        // cannot manage composition with TextComposition instance.  Although,
+        // this case shouldn't occur.
+        if (NS_WARN_IF(!mIMContext)) {
+            return this;
+        }
+        return mIMContext.get();
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nullptr;
     }
 }
 
 void
 nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
@@ -6290,23 +6299,18 @@ nsWindow::SetInputContext(const InputCon
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
   InputContext context;
   if (!mIMContext) {
       context.mIMEState.mEnabled = IMEState::DISABLED;
       context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-      // If IME context isn't available on this widget, we should set |this|
-      // instead of nullptr since nullptr means that the platform has only one
-      // context per process.
-      context.mNativeIMEContext = this;
   } else {
       context = mIMContext->GetInputContext();
-      context.mNativeIMEContext = mIMContext;
   }
   return context;
 }
 
 nsIMEUpdatePreference
 nsWindow::GetIMEUpdatePreference()
 {
     if (!mIMContext) {
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -99,17 +99,22 @@ typedef void* nsNativeWidget;
 #define NS_NATIVE_SCREEN      9
 // The toplevel GtkWidget containing this nsIWidget:
 #define NS_NATIVE_SHELLWIDGET 10
 // Has to match to NPNVnetscapeWindow, and shareable across processes
 // HWND on Windows and XID on X11
 #define NS_NATIVE_SHAREABLE_WINDOW 11
 #define NS_NATIVE_OPENGL_CONTEXT   12
 // See RegisterPluginWindowForRemoteUpdates
-#define NS_NATIVE_PLUGIN_ID            13
+#define NS_NATIVE_PLUGIN_ID        13
+// This is available only with GetNativeData().  Anybody shouldn't access this
+// pointer as a valid pointer since the result may be special value like
+// NS_ONLY_ONE_NATIVE_IME_CONTEXT.  So, the result is just an identifier of
+// distinguishing a text composition is caused by which native IME context.
+#define NS_NATIVE_IME_CONTEXT      14
 #ifdef XP_MACOSX
 #define NS_NATIVE_PLUGIN_PORT_QD    100
 #define NS_NATIVE_PLUGIN_PORT_CG    101
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -659,16 +659,20 @@ nsWindow::GetNativeData(uint32_t aDataTy
 #endif
         break;
     }
     case NS_NATIVE_PLUGIN_PORT:
     case NS_NATIVE_GRAPHIC:
     case NS_NATIVE_SHELLWIDGET: {
         break;
     }
+    case NS_NATIVE_IME_CONTEXT:
+        // Our qt widget looks like using only one context per process.
+        // However, it's better to set the context's pointer.
+        return qApp->inputMethod();
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nullptr;
     }
     LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
     return nullptr;
 }
 
@@ -711,20 +715,16 @@ nsWindow::SetInputContext(const InputCon
             break;
     }
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
     mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-    // Our qt widget looks like using only one context per process.
-    // However, it's better to set the context's pointer.
-    mInputContext.mNativeIMEContext = qApp->inputMethod();
-
     return mInputContext;
 }
 
 NS_IMETHODIMP
 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
 {
     NS_PRECONDITION(aNewParent, "");
 
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -831,17 +831,16 @@ nsWindow::SetInputContext(const InputCon
 {
     //TODO: actually show VKB
     mInputContext = aContext;
 }
 
 NS_IMETHODIMP_(mozilla::widget::InputContext)
 nsWindow::GetInputContext()
 {
-    mInputContext.mNativeIMEContext = nullptr;
     return mInputContext;
 }
 
 void
 nsWindow::SetBackgroundColor(const nscolor &aColor)
 {
     mNativeView.backgroundColor = [UIColor colorWithRed:NS_GET_R(aColor)
                                    green:NS_GET_G(aColor)
@@ -874,16 +873,20 @@ void* nsWindow::GetNativeData(uint32_t a
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
 
     case NS_NATIVE_PLUGIN_PORT:
         // not implemented
         break;
+
+    case NS_NATIVE_IME_CONTEXT:
+      retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+      break;
   }
 
   return retVal;
 }
 
 CGFloat
 nsWindow::BackingScaleFactor()
 {
--- a/widget/windows/IMMHandler.cpp
+++ b/widget/windows/IMMHandler.cpp
@@ -181,16 +181,40 @@ IMEContext::IMEContext(HWND aWnd)
 }
 
 IMEContext::IMEContext(nsWindow* aWindow)
   : mWnd(aWindow->GetWindowHandle())
   , mIMC(::ImmGetContext(aWindow->GetWindowHandle()))
 {
 }
 
+void
+IMEContext::Init(HWND aWnd)
+{
+  Clear();
+  mWnd = aWnd;
+  mIMC = ::ImmGetContext(mWnd);
+}
+
+void
+IMEContext::Init(nsWindow* aWindow)
+{
+  Init(aWindow->GetWindowHandle());
+}
+
+void
+IMEContext::Clear()
+{
+  if (mWnd && mIMC) {
+    ::ImmReleaseContext(mWnd, mIMC);
+  }
+  mWnd = nullptr;
+  mIMC = nullptr;
+}
+
 /******************************************************************************
  * IMMHandler
  ******************************************************************************/
 
 static UINT sWM_MSIME_MOUSE = 0; // mouse message for MSIME 98/2000
 
 WritingMode IMMHandler::sWritingModeOfCompositionFont;
 nsString IMMHandler::sIMEName;
--- a/widget/windows/IMMHandler.h
+++ b/widget/windows/IMMHandler.h
@@ -21,32 +21,39 @@ class nsWindow;
 namespace mozilla {
 namespace widget {
 
 struct MSGResult;
 
 class IMEContext final
 {
 public:
+  IMEContext()
+    : mWnd(nullptr)
+    , mIMC(nullptr)
+  {
+  }
+
   explicit IMEContext(HWND aWnd);
   explicit IMEContext(nsWindow* aWindow);
 
   ~IMEContext()
   {
-    if (mIMC) {
-      ::ImmReleaseContext(mWnd, mIMC);
-      mIMC = nullptr;
-    }
+    Clear();
   }
 
   HIMC get() const
   {
     return mIMC;
   }
 
+  void Init(HWND aWnd);
+  void Init(nsWindow* aWindow);
+  void Clear();
+
   bool IsValid() const
   {
     return !!mIMC;
   }
 
   void SetOpenState(bool aOpen) const
   {
     if (!mIMC) {
@@ -85,21 +92,16 @@ public:
       return false;
     }
     ::ImmReleaseContext(mWnd, mIMC);
     mIMC = nullptr;
     return true;
   }
 
 protected:
-  IMEContext()
-  {
-    MOZ_CRASH("Don't create IMEContext without window handle");
-  }
-
   IMEContext(const IMEContext& aOther)
   {
     MOZ_CRASH("Don't copy IMEContext");
   }
 
   HWND mWnd;
   HIMC mIMC;
 };
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -89,18 +89,41 @@ IMEHandler::Terminate()
   }
 #endif // #ifdef NS_ENABLE_TSF
 
   IMMHandler::Terminate();
 }
 
 // static
 void*
-IMEHandler::GetNativeData(uint32_t aDataType)
+IMEHandler::GetNativeData(nsWindow* aWindow, uint32_t aDataType)
 {
+  if (aDataType == NS_NATIVE_IME_CONTEXT) {
+#ifdef NS_ENABLE_TSF
+    if (IsTSFAvailable()) {
+      return TSFTextStore::GetThreadManager();
+    }
+#endif // #ifdef NS_ENABLE_TSF
+    IMEContext context(aWindow);
+    if (context.IsValid()) {
+      return context.get();
+    }
+    // If IMC isn't associated with the window, IME is disabled on the window
+    // now.  In such case, we should return default IMC instead.
+    const IMEContext& defaultIMC = aWindow->DefaultIMC();
+    if (defaultIMC.IsValid()) {
+      return defaultIMC.get();
+    }
+    // If there is no default IMC, we should return the pointer to the window
+    // since if we return nullptr, IMEStateManager cannot manage composition
+    // with TextComposition instance.  This is possible if no IME is installed,
+    // but composition may occur with dead key sequence.
+    return aWindow;
+  }
+
 #ifdef NS_ENABLE_TSF
   void* result = TSFTextStore::GetNativeData(aDataType);
   if (!result || !(*(static_cast<void**>(result)))) {
     return nullptr;
   }
   // XXX During the TSF module test, sIsInTSFMode must be true.  After that,
   //     the value should be restored but currently, there is no way for that.
   //     When the TSF test is enabled again, we need to fix this.  Perhaps,
@@ -375,24 +398,21 @@ IMEHandler::SetInputContext(nsWindow* aW
   sPluginHasFocus = (aInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
 
   bool enable = WinUtils::IsIMEEnabled(aInputContext);
   bool adjustOpenState = (enable &&
     aInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE);
   bool open = (adjustOpenState &&
     aInputContext.mIMEState.mOpen == IMEState::OPEN);
 
-  aInputContext.mNativeIMEContext = nullptr;
-
 #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()) {
-      aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
       if (sIsIMMEnabled) {
         // Associate IME context for IMM-IMEs.
         AssociateIMEContext(aWindow, enable);
       } 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);
       }
@@ -408,25 +428,16 @@ IMEHandler::SetInputContext(nsWindow* aW
 #endif // #ifdef NS_ENABLE_TSF
 
   AssociateIMEContext(aWindow, enable);
 
   IMEContext context(aWindow);
   if (adjustOpenState) {
     context.SetOpenState(open);
   }
-
-  if (aInputContext.mNativeIMEContext) {
-    return;
-  }
-
-  // The old InputContext must store the default IMC or old TextStore.
-  // When IME context is disassociated from the window, use it.
-  aInputContext.mNativeIMEContext = enable ?
-    static_cast<void*>(context.get()) : oldInputContext.mNativeIMEContext;
 }
 
 // static
 void
 IMEHandler::AssociateIMEContext(nsWindow* aWindow, bool aEnable)
 {
   IMEContext context(aWindow);
   if (aEnable) {
@@ -447,35 +458,29 @@ IMEHandler::InitInputContext(nsWindow* a
   // For a11y, the default enabled state should be 'enabled'.
   aInputContext.mIMEState.mEnabled = IMEState::ENABLED;
 
 #ifdef NS_ENABLE_TSF
   if (sIsInTSFMode) {
     TSFTextStore::SetInputContext(aWindow, aInputContext,
       InputContextAction(InputContextAction::CAUSE_UNKNOWN,
                          InputContextAction::GOT_FOCUS));
-    aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
-    MOZ_ASSERT(aInputContext.mNativeIMEContext);
     // IME context isn't necessary in pure TSF mode.
     if (!sIsIMMEnabled) {
       AssociateIMEContext(aWindow, false);
     }
     return;
   }
 #endif // #ifdef NS_ENABLE_TSF
 
-  // NOTE: mNativeIMEContext may be null if IMM module isn't installed.
+#ifdef DEBUG
+  // NOTE: IMC may be null if IMM module isn't installed.
   IMEContext context(aWindow);
-  aInputContext.mNativeIMEContext = static_cast<void*>(context.get());
-  MOZ_ASSERT(aInputContext.mNativeIMEContext || !CurrentKeyboardLayoutHasIME());
-  // If no IME context is available, we should set the widget's pointer since
-  // nullptr indicates there is only one context per process on the platform.
-  if (!aInputContext.mNativeIMEContext) {
-    aInputContext.mNativeIMEContext = static_cast<void*>(aWindow);
-  }
+  MOZ_ASSERT(context.IsValid() || !CurrentKeyboardLayoutHasIME());
+#endif // #ifdef DEBUG
 }
 
 #ifdef DEBUG
 // static
 bool
 IMEHandler::CurrentKeyboardLayoutHasIME()
 {
 #ifdef NS_ENABLE_TSF
--- a/widget/windows/WinIMEHandler.h
+++ b/widget/windows/WinIMEHandler.h
@@ -29,19 +29,19 @@ struct MSGResult;
  */
 class IMEHandler final
 {
 public:
   static void Initialize();
   static void Terminate();
 
   /**
-   * Returns TSF related native data.
+   * Returns TSF related native data or native IME context.
    */
-  static void* GetNativeData(uint32_t aDataType);
+  static void* GetNativeData(nsWindow* aWindow, uint32_t aDataType);
 
   /**
    * ProcessRawKeyMessage() message is called before calling TranslateMessage()
    * and DispatchMessage().  If this returns true, the message is consumed.
    * Then, caller must not perform TranslateMessage() nor DispatchMessage().
    */
   static bool ProcessRawKeyMessage(const MSG& aMsg);
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -651,16 +651,17 @@ nsWindow::Create(nsIWidget* aParent,
   // Starting with Windows XP, a process always runs within a terminal services
   // session. In order to play nicely with RDP, fast user switching, and the
   // lock screen, we should be handling WM_WTSSESSION_CHANGE. We must register
   // our HWND in order to receive this message.
   DebugOnly<BOOL> wtsRegistered = ::WTSRegisterSessionNotification(mWnd,
                                                        NOTIFY_FOR_THIS_SESSION);
   NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
 
+  mDefaultIMC.Init(this);
   IMEHandler::InitInputContext(this, mInputContext);
 
   // If the internal variable set by the config.trim_on_minimize pref has not
   // been initialized, and if this is the hidden window (conveniently created
   // before any visible windows, and after the profile has been initialized),
   // do some initialization work.
   if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
     // Our internal trim prevention logic is effective on 2K/XP at maintaining
@@ -3144,20 +3145,21 @@ void* nsWindow::GetNativeData(uint32_t a
       // XXX:  This is sleezy!!  Remember to Release the DC after using it!
 #ifdef MOZ_XUL
       return (void*)(eTransparencyTransparent == mTransparencyMode) ?
         mMemoryDC : ::GetDC(mWnd);
 #else
       return (void*)::GetDC(mWnd);
 #endif
 
+    case NS_NATIVE_IME_CONTEXT:
     case NS_NATIVE_TSF_THREAD_MGR:
     case NS_NATIVE_TSF_CATEGORY_MGR:
     case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
-      return IMEHandler::GetNativeData(aDataType);
+      return IMEHandler::GetNativeData(this, aDataType);
 
     default:
       break;
   }
 
   return nullptr;
 }
 
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -39,16 +39,18 @@
 #include "oleacc.h"
 #include "mozilla/a11y/Accessible.h"
 #endif
 
 #include "nsUXThemeData.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIIdleServiceInternal.h"
 
+#include "IMMHandler.h"
+
 /**
  * Forward class definitions
  */
 
 class nsNativeDragTarget;
 class nsIRollupListener;
 class imgIContainer;
 
@@ -66,16 +68,17 @@ struct MSGResult;
 class nsWindow : public nsWindowBase
 {
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::widget::WindowHook WindowHook;
   typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
   typedef mozilla::widget::NativeKey NativeKey;
   typedef mozilla::widget::MSGResult MSGResult;
+  typedef mozilla::widget::IMEContext IMEContext;
 
 public:
   nsWindow();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   friend class nsWindowGfx;
 
@@ -287,16 +290,18 @@ public:
 
   bool                    const DestroyCalled() { return mDestroyCalled; }
 
   bool IsPopup();
   virtual bool ShouldUseOffMainThreadCompositing();
 
   bool CaptureWidgetOnScreen(RefPtr<mozilla::gfx::DrawTarget> aDT);
 
+  const IMEContext& DefaultIMC() const { return mDefaultIMC; }
+
 protected:
   virtual ~nsWindow();
 
   virtual void WindowUsesOMTC() override;
   virtual void RegisterTouchWindow() override;
 
   virtual nsresult NotifyIMEInternal(
                      const IMENotification& aIMENotification) override;
@@ -467,16 +472,17 @@ protected:
 protected:
   nsCOMPtr<nsIWidget>   mParent;
   nsIntSize             mLastSize;
   nsIntPoint            mLastPoint;
   HWND                  mWnd;
   HWND                  mTransitionWnd;
   WNDPROC               mPrevWndProc;
   HBRUSH                mBrush;
+  IMEContext            mDefaultIMC;
   bool                  mIsTopWidgetWindow;
   bool                  mInDtor;
   bool                  mIsVisible;
   bool                  mUnicodeWidget;
   bool                  mPainting;
   bool                  mTouchWindow;
   bool                  mDisplayPanFeedback;
   bool                  mHideChrome;