Bug 1377672 - part3: IMEStateManager::NotifyIME() should ignore notifications and requests which comes from unexpected process r?smaug, m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 06 Jul 2017 00:47:40 +0900
changeset 605194 faa5e384a7e166d9d7ea46aa0ef89b1e6c8dc652
parent 605193 2f01e62d6867ae1c79aed7c9fdc9b1087a842092
child 605195 caba59e091625c356bc0098fff2bf942cfc2bbef
push id67319
push usermasayuki@d-toybox.com
push dateFri, 07 Jul 2017 05:35:43 +0000
reviewerssmaug, m_kato
bugs1377672
milestone56.0a1
Bug 1377672 - part3: IMEStateManager::NotifyIME() should ignore notifications and requests which comes from unexpected process r?smaug, m_kato IME should receive notifications and requests only from proper process. E.g., IME shouldn't commit composition by a request which came from previous focused process. This patch makes that IMEStateManager::NotifyIME() takes pointer to TabParent optionally. If the request or notification came from remote process, it should be non-nullptr. Then, this makes it ignore notifications and requests from unexpected process. Note that this patch also touches some gfx headers because they use |ipc::| but compiler is confused at the ambiguousness between |mozilla::ipc::| and |mozilla::dom::ipc::|. Finally, this patch changes the NS_ASSERTION in IMEHandler::OnDestroyWindow() to MOZ_ASSERT because the orange caused by the NS_ASSERTION was not realized since there was already an intermittent orange bug caused by different NS_ASSERTION. MozReview-Commit-ID: 9CgKXQRJWmN
dom/events/IMEStateManager.cpp
dom/events/IMEStateManager.h
dom/events/TextComposition.cpp
dom/events/TextComposition.h
dom/ipc/TabParent.cpp
gfx/ipc/GPUProcessHost.h
gfx/ipc/GPUProcessManager.h
widget/ContentCache.cpp
widget/ContentCache.h
widget/windows/WinIMEHandler.cpp
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -131,30 +131,42 @@ GetIMEStateSetOpenName(IMEState::Open aO
       return "OPEN";
     case IMEState::CLOSED:
       return "CLOSED";
     default:
       return "illegal value";
   }
 }
 
+static bool
+IsSameProcess(const TabParent* aTabParent1, const TabParent* aTabParent2)
+{
+  if (aTabParent1 == aTabParent2) {
+    return true;
+  }
+  if (!aTabParent1 != !aTabParent2) {
+    return false;
+  }
+  return aTabParent1->Manager() == aTabParent2->Manager();
+}
+
 StaticRefPtr<nsIContent> IMEStateManager::sContent;
 StaticRefPtr<nsPresContext> IMEStateManager::sPresContext;
 nsIWidget* IMEStateManager::sWidget = nullptr;
 nsIWidget* IMEStateManager::sFocusedIMEWidget = nullptr;
+StaticRefPtr<TabParent> IMEStateManager::sFocusedIMETabParent;
 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
 IMEStateManager::Init()
 {
   Preferences::AddBoolVarCache(
     &sCheckForIMEUnawareWebApps,
     "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition",
@@ -221,17 +233,17 @@ IMEStateManager::StopIMEStateManagement(
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("StopIMEStateManagement()"));
 
   // NOTE: Don't set input context from here since this has already lost
   //       the rights to change input context.
 
   if (sTextCompositions && sPresContext) {
-    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext);
+    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext, sActiveTabParent);
   }
   sActiveInputContextWidget = nullptr;
   sPresContext = nullptr;
   sContent = nullptr;
   sActiveTabParent = nullptr;
   DestroyIMEContentObserver();
 }
 
@@ -439,17 +451,17 @@ IMEStateManager::OnChangeFocusInternal(n
   bool focusActuallyChanging =
     (sContent != aContent || sPresContext != aPresContext ||
      oldWidget != newWidget || sActiveTabParent != newTabParent);
 
   if (oldWidget && focusActuallyChanging) {
     // If we're deactivating, we shouldn't commit composition forcibly because
     // the user may want to continue the composition.
     if (aPresContext) {
-      NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
+      NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget, sFocusedIMETabParent);
     }
   }
 
   if (sActiveIMEContentObserver) {
     // If there is active IMEContentObserver, it means that focused content was
     // in this process.  So, if a tab parent gets focus, it means that the
     // focused editor in this process is being blurred.
     if (newTabParent) {
@@ -473,21 +485,17 @@ IMEStateManager::OnChangeFocusInternal(n
 
   if (!aPresContext) {
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("  OnChangeFocusInternal(), "
        "no nsPresContext is being activated"));
     return NS_OK;
   }
 
-  nsIContentParent* currentContentParent =
-    sActiveTabParent ? sActiveTabParent->Manager() : nullptr;
-  nsIContentParent* newContentParent =
-    newTabParent ? newTabParent->Manager() : nullptr;
-  if (sActiveTabParent && currentContentParent != newContentParent) {
+  if (sActiveTabParent && !IsSameProcess(sActiveTabParent, newTabParent)) {
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("  OnChangeFocusInternal(), notifying previous "
        "focused child process of parent process or another child process "
        "getting focus"));
     Unused << sActiveTabParent->SendStopIMEStateManagement();
   }
 
   if (NS_WARN_IF(!newWidget)) {
@@ -560,17 +568,18 @@ IMEStateManager::OnChangeFocusInternal(n
            "neither focus nor IME state is changing"));
         return NS_OK;
       }
       aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
 
       // Even if focus isn't changing actually, we should commit current
       // composition here since the IME state is changing.
       if (sPresContext && oldWidget && !focusActuallyChanging) {
-        NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
+        NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
+                  sFocusedIMETabParent);
       }
     } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
       // If aContent isn't null or aContent is null but editable, somebody gets
       // focus.
       bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
       aAction.mFocusChange =
         gotFocus ? InputContextAction::GOT_FOCUS :
                    InputContextAction::LOST_FOCUS;
@@ -918,17 +927,17 @@ IMEStateManager::UpdateIMEState(const IM
   if (NS_WARN_IF(widget->Destroyed())) {
     MOZ_LOG(sISMLog, LogLevel::Error,
       ("  UpdateIMEState(), widget has gone during getting input context"));
     return;
   }
 
   if (updateIMEState) {
     // commit current composition before modifying IME state.
-    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
+    NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget, sFocusedIMETabParent);
     if (NS_WARN_IF(widget->Destroyed())) {
       MOZ_LOG(sISMLog, LogLevel::Error,
         ("  UpdateIMEState(), widget has gone during committing composition"));
       return;
     }
   }
 
   if (createTextStateManager) {
@@ -1438,191 +1447,193 @@ IMEStateManager::OnCompositionEventDisca
   }
   composition->OnCompositionEventDiscarded(aCompositionEvent);
 }
 
 // static
 nsresult
 IMEStateManager::NotifyIME(IMEMessage aMessage,
                            nsIWidget* aWidget,
-                           bool aOriginIsRemote)
+                           TabParent* aTabParent)
 {
   return IMEStateManager::NotifyIME(IMENotification(aMessage), aWidget,
-                                    aOriginIsRemote);
+                                    aTabParent);
 }
 
 // static
 nsresult
 IMEStateManager::NotifyIME(const IMENotification& aNotification,
                            nsIWidget* aWidget,
-                           bool aOriginIsRemote)
+                           TabParent* aTabParent)
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("NotifyIME(aNotification={ mMessage=%s }, "
-     "aWidget=0x%p, aOriginIsRemote=%s), sFocusedIMEWidget=0x%p, "
-     "sRemoteHasFocus=%s",
+     "aWidget=0x%p, aTabParent=0x%p), sFocusedIMEWidget=0x%p, "
+     "sActiveTabParent=0x%p, sFocusedIMETabParent=0x%p, "
+     "IsSameProcess(aTabParent, sActiveTabParent)=%s, "
+     "IsSameProcess(aTabParent, sFocusedIMETabParent)=%s",
      ToChar(aNotification.mMessage), aWidget,
-     GetBoolName(aOriginIsRemote), sFocusedIMEWidget,
-     GetBoolName(sRemoteHasFocus)));
+     aTabParent, sFocusedIMEWidget, sActiveTabParent.get(),
+     sFocusedIMETabParent.get(),
+     GetBoolName(IsSameProcess(aTabParent, sActiveTabParent)),
+     GetBoolName(IsSameProcess(aTabParent, sFocusedIMETabParent))));
 
   if (NS_WARN_IF(!aWidget)) {
     MOZ_LOG(sISMLog, LogLevel::Error,
       ("  NotifyIME(), FAILED due to no widget"));
     return NS_ERROR_INVALID_ARG;
   }
 
   switch (aNotification.mMessage) {
     case NOTIFY_IME_OF_FOCUS: {
+      // If focus notification comes from a remote process which already lost
+      // focus, we shouldn't accept the focus notification.  Then, following
+      // notifications from the process will be ignored.
+      if (NS_WARN_IF(!IsSameProcess(aTabParent, sActiveTabParent))) {
+        MOZ_ASSERT(aTabParent,
+          "Why was the input context initialized for a remote process but "
+          "does this process get IME focus?");
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received focus notification is ignored "
+           "because input context was initialized for %s, perhaps, it came "
+           "from a busy remote process",
+           sActiveTabParent ? "another remote process" : "current process"));
+        return NS_OK;
+      }
+      // If there is pending blur notification for current focused IME,
+      // we should notify IME of blur by ourselves.  Then, we should ignore
+      // following notifications coming from the process.
       if (sFocusedIMEWidget) {
-        if (NS_WARN_IF(!sRemoteHasFocus && !aOriginIsRemote)) {
-          MOZ_LOG(sISMLog, LogLevel::Error,
-            ("  NotifyIME(), although, this process is "
-             "getting IME focus but there was focused IME widget"));
-        } else {
-          MOZ_LOG(sISMLog, LogLevel::Info,
-            ("  NotifyIME(), tries to notify IME of "
-             "blur first because remote process's blur notification hasn't "
-             "been received yet..."));
-        }
+        MOZ_ASSERT(sFocusedIMETabParent || aTabParent,
+          "This case shouldn't be caused by focus move in this process");
         nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
         sFocusedIMEWidget = nullptr;
-        sRemoteHasFocus = false;
+        sFocusedIMETabParent = nullptr;
         focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
       }
-      sRemoteHasFocus = aOriginIsRemote;
+      sFocusedIMETabParent = aTabParent;
       sFocusedIMEWidget = aWidget;
       nsCOMPtr<nsIWidget> widget(aWidget);
       return widget->NotifyIME(aNotification);
     }
     case NOTIFY_IME_OF_BLUR: {
-      if (!sRemoteHasFocus && aOriginIsRemote) {
-        MOZ_LOG(sISMLog, LogLevel::Info,
-          ("  NotifyIME(), received blur notification "
-           "after another one has focus, nothing to do..."));
+      if (!IsSameProcess(aTabParent, sFocusedIMETabParent)) {
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received blur notification is ignored "
+           "because it's not from current focused IME process"));
         return NS_OK;
       }
-      if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
+      if (!sFocusedIMEWidget) {
         MOZ_LOG(sISMLog, LogLevel::Error,
-          ("  NotifyIME(), FAILED, received blur "
-           "notification from this process but the remote has focus"));
-        return NS_OK;
-      }
-      if (!sFocusedIMEWidget && aOriginIsRemote) {
-        MOZ_LOG(sISMLog, LogLevel::Info,
-          ("  NotifyIME(), received blur notification "
-           "but the remote has already lost focus"));
-        return NS_OK;
-      }
-      if (NS_WARN_IF(!sFocusedIMEWidget)) {
-        MOZ_LOG(sISMLog, LogLevel::Error,
-          ("  NotifyIME(), FAILED, received blur "
-           "notification but there is no focused IME widget"));
+          ("  NotifyIME(), WARNING, received blur notification but there is "
+           "no focused IME widget"));
         return NS_OK;
       }
       if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
-        MOZ_LOG(sISMLog, LogLevel::Error,
-          ("  NotifyIME(), FAILED, received blur "
-           "notification but there is no focused IME widget"));
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received blur notification is ignored "
+           "because it's not for current focused IME widget"));
         return NS_OK;
       }
       nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
       sFocusedIMEWidget = nullptr;
-      sRemoteHasFocus = false;
+      sFocusedIMETabParent = nullptr;
       return focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
     }
     case NOTIFY_IME_OF_SELECTION_CHANGE:
     case NOTIFY_IME_OF_TEXT_CHANGE:
     case NOTIFY_IME_OF_POSITION_CHANGE:
     case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
     case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: {
-      if (!sRemoteHasFocus && aOriginIsRemote) {
-        MOZ_LOG(sISMLog, LogLevel::Info,
-          ("  NotifyIME(), received content change "
-           "notification from the remote but it's already lost focus"));
-        return NS_OK;
-      }
-      if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
-        MOZ_LOG(sISMLog, LogLevel::Error,
-          ("  NotifyIME(), FAILED, received content "
-           "change notification from this process but the remote has already "
-           "gotten focus"));
+      if (!IsSameProcess(aTabParent, sFocusedIMETabParent)) {
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received content change notification "
+           "is ignored because it's not from current focused IME process"));
         return NS_OK;
       }
       if (!sFocusedIMEWidget) {
-        MOZ_LOG(sISMLog, LogLevel::Info,
-          ("  NotifyIME(), received content change "
-           "notification but there is no focused IME widget"));
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received content change notification "
+           "is ignored because there is no focused IME widget"));
         return NS_OK;
       }
       if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
-        MOZ_LOG(sISMLog, LogLevel::Error,
-          ("  NotifyIME(), FAILED, received content "
-           "change notification for IME which has already lost focus, so, "
-           "nothing to do..."));
+        MOZ_LOG(sISMLog, LogLevel::Warning,
+          ("  NotifyIME(), WARNING, the received content change notification "
+           "is ignored because it's not for current focused IME widget"));
         return NS_OK;
       }
       nsCOMPtr<nsIWidget> widget(aWidget);
       return widget->NotifyIME(aNotification);
     }
     default:
       // Other notifications should be sent only when there is composition.
       // So, we need to handle the others below.
       break;
   }
 
-  RefPtr<TextComposition> composition;
-  if (sTextCompositions) {
-    composition = sTextCompositions->GetCompositionFor(aWidget);
+  if (!sTextCompositions) {
+    MOZ_LOG(sISMLog, LogLevel::Info,
+      ("  NotifyIME(), the request to IME is ignored because "
+       "there have been no compositions yet"));
+    return NS_OK;
   }
 
-  bool isSynthesizedForTests =
-    composition && composition->IsSynthesizedForTests();
+  RefPtr<TextComposition> composition =
+    sTextCompositions->GetCompositionFor(aWidget);
+  if (!composition) {
+    MOZ_LOG(sISMLog, LogLevel::Info,
+      ("  NotifyIME(), the request to IME is ignored because "
+       "there is no active composition"));
+    return NS_OK;
+  }
 
-  MOZ_LOG(sISMLog, LogLevel::Info,
-    ("  NotifyIME(), composition=0x%p, "
-     "composition->IsSynthesizedForTests()=%s",
-     composition.get(), GetBoolName(isSynthesizedForTests)));
+  if (!IsSameProcess(aTabParent, composition->GetTabParent())) {
+    MOZ_LOG(sISMLog, LogLevel::Warning,
+      ("  NotifyIME(), WARNING, the request to IME is ignored because "
+       "it does not come from the remote process which has the composition "
+       "on aWidget"));
+    return NS_OK;
+  }
 
   switch (aNotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
-      return composition ?
-        composition->RequestToCommit(aWidget, false) : NS_OK;
+      return composition->RequestToCommit(aWidget, false);
     case REQUEST_TO_CANCEL_COMPOSITION:
-      return composition ?
-        composition->RequestToCommit(aWidget, true) : NS_OK;
+      return composition->RequestToCommit(aWidget, true);
     default:
       MOZ_CRASH("Unsupported notification");
   }
   MOZ_CRASH(
     "Failed to handle the notification for non-synthesized composition");
   return NS_ERROR_FAILURE;
 }
 
 // static
 nsresult
 IMEStateManager::NotifyIME(IMEMessage aMessage,
                            nsPresContext* aPresContext,
-                           bool aOriginIsRemote)
+                           TabParent* aTabParent)
 {
   MOZ_LOG(sISMLog, LogLevel::Info,
-    ("NotifyIME(aMessage=%s, aPresContext=0x%p, aOriginIsRemote=%s)",
-     ToChar(aMessage), aPresContext, GetBoolName(aOriginIsRemote)));
+    ("NotifyIME(aMessage=%s, aPresContext=0x%p, aTabParent=0x%p)",
+     ToChar(aMessage), aPresContext, aTabParent));
 
   if (NS_WARN_IF(!CanHandleWith(aPresContext))) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsIWidget* widget = aPresContext->GetRootWidget();
   if (NS_WARN_IF(!widget)) {
     MOZ_LOG(sISMLog, LogLevel::Error,
       ("  NotifyIME(), FAILED due to no widget for the "
        "nsPresContext"));
     return NS_ERROR_NOT_AVAILABLE;
   }
-  return NotifyIME(aMessage, widget, aOriginIsRemote);
+  return NotifyIME(aMessage, widget, aTabParent);
 }
 
 // static
 bool
 IMEStateManager::IsEditable(nsINode* node)
 {
   if (node->IsEditable()) {
     return true;
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -219,23 +219,23 @@ public:
     GetTextCompositionFor(nsPresContext* aPresContext);
 
   /**
    * Send a notification to IME.  It depends on the IME or platform spec what
    * will occur (or not occur).
    */
   static nsresult NotifyIME(const IMENotification& aNotification,
                             nsIWidget* aWidget,
-                            bool aOriginIsRemote = false);
+                            TabParent* aTabParent = nullptr);
   static nsresult NotifyIME(IMEMessage aMessage,
                             nsIWidget* aWidget,
-                            bool aOriginIsRemote = false);
+                            TabParent* aTabParent = nullptr);
   static nsresult NotifyIME(IMEMessage aMessage,
                             nsPresContext* aPresContext,
-                            bool aOriginIsRemote = false);
+                            TabParent* aTabParent = nullptr);
 
   static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
                                       nsIContent* aContent);
 
   /**
    * Returns active IMEContentObserver but may be nullptr if focused content
    * isn't editable or focus in a remote process.
    */
@@ -275,21 +275,20 @@ protected:
   // document has focus but there is no focused element, sContent may be
   // nullptr.
   static StaticRefPtr<nsIContent> sContent;
   static StaticRefPtr<nsPresContext> sPresContext;
   // sWidget is cache for the root widget of sPresContext.  Even afer
   // sPresContext has gone, we need to clean up some IME state on the widget
   // if the widget is available.
   static nsIWidget* sWidget;
-  // sFocusedIMEWidget is, the widget which was sent to "focus" notification
-  // from IMEContentObserver and not yet sent "blur" notification.
-  // So, if this is not nullptr, the widget needs to receive "blur"
-  // notification.
+  // sFocusedIMETabParent is the tab parent, which send "focus" notification to
+  // sFocusedIMEWidget (and didn't yet sent "blur" notification).
   static nsIWidget* sFocusedIMEWidget;
+  static StaticRefPtr<TabParent> sFocusedIMETabParent;
   // sActiveInputContextWidget is the last widget whose SetInputContext() is
   // called.  This is important to reduce sync IPC cost with parent process.
   // If IMEStateManager set input context to different widget, PuppetWidget can
   // return cached input context safely.
   static nsIWidget* sActiveInputContextWidget;
   static StaticRefPtr<TabParent> sActiveTabParent;
   // sActiveIMEContentObserver points to the currently active
   // IMEContentObserver.  This is null if there is no focused editor.
@@ -303,17 +302,16 @@ protected:
 
   // 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
   {
   public:
     GettingNewIMEStateBlocker()
       : mOldValue(IMEStateManager::sIsGettingNewIMEState)
     {
       IMEStateManager::sIsGettingNewIMEState = true;
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -611,17 +611,17 @@ TextComposition::RequestToCommit(nsIWidg
   }
   return NS_OK;
 }
 
 nsresult
 TextComposition::NotifyIME(IMEMessage aMessage)
 {
   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
-  return IMEStateManager::NotifyIME(aMessage, mPresContext);
+  return IMEStateManager::NotifyIME(aMessage, mPresContext, mTabParent);
 }
 
 void
 TextComposition::EditorWillHandleCompositionChangeEvent(
                    const WidgetCompositionEvent* aCompositionChangeEvent)
 {
   mIsComposing = aCompositionChangeEvent->IsComposing();
   mRanges = aCompositionChangeEvent->mRanges;
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -70,16 +70,21 @@ public:
   // XXX We should return |const TextRangeArray*| here, but it causes compile
   //     error due to inaccessible Release() method.
   TextRangeArray* GetRanges() const { return mRanges; }
   // Returns the widget which is proper to call NotifyIME().
   nsIWidget* GetWidget() const
   {
     return mPresContext ? mPresContext->GetRootWidget() : nullptr;
   }
+  // Returns the tab parent which has this composition in its remote process.
+  TabParent* GetTabParent() const
+  {
+    return mTabParent;
+  }
   // Returns true if the composition is started with synthesized event which
   // came from nsDOMWindowUtils.
   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
 
   const widget::NativeIMEContext& GetNativeIMEContext() const
   {
     return mNativeContext;
   }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -138,16 +138,17 @@ NS_IMPL_ISUPPORTS(TabParent,
                   nsIWebBrowserPersistable)
 
 TabParent::TabParent(nsIContentParent* aManager,
                      const TabId& aTabId,
                      const TabContext& aContext,
                      uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
+  , mContentCache(*this)
   , mRect(0, 0, 0, 0)
   , mDimensions(0, 0)
   , mOrientation(0)
   , mDPI(0)
   , mRounding(0)
   , mDefaultScale(0)
   , mUpdatedDimensions(false)
   , mSizeMode(nsSizeMode_Normal)
@@ -1740,17 +1741,17 @@ TabParent::RecvNotifyIMEFocus(const Cont
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aRequests = IMENotificationRequests();
     return IPC_OK();
   }
 
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
-  IMEStateManager::NotifyIME(aIMENotification, widget, true);
+  IMEStateManager::NotifyIME(aIMENotification, widget, this);
 
   if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
     *aRequests = widget->IMENotificationRequestsRef();
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
@@ -1819,17 +1820,17 @@ TabParent::RecvNotifyIMEMouseButtonEvent
              bool* aConsumedByIME)
 {
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     *aConsumedByIME = false;
     return IPC_OK();
   }
-  nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, true);
+  nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, this);
   *aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
                                        const IMENotification& aIMENotification)
 {
--- a/gfx/ipc/GPUProcessHost.h
+++ b/gfx/ipc/GPUProcessHost.h
@@ -22,17 +22,17 @@ class GPUChild;
 
 // GPUProcessHost is the "parent process" container for a subprocess handle and
 // IPC connection. It owns the parent process IPDL actor, which in this case,
 // is a GPUChild.
 //
 // GPUProcessHosts are allocated and managed by GPUProcessManager. For all
 // intents and purposes it is a singleton, though more than one may be allocated
 // at a time due to its shutdown being asynchronous.
-class GPUProcessHost final : public ipc::GeckoChildProcessHost
+class GPUProcessHost final : public mozilla::ipc::GeckoChildProcessHost
 {
   friend class GPUChild;
 
 public:
   class Listener {
   public:
     virtual void OnProcessLaunchComplete(GPUProcessHost* aHost)
     {}
@@ -116,17 +116,17 @@ private:
   void KillHard(const char* aReason);
 
   void DestroyProcess();
 
 private:
   DISALLOW_COPY_AND_ASSIGN(GPUProcessHost);
 
   Listener* mListener;
-  ipc::TaskFactory<GPUProcessHost> mTaskFactory;
+  mozilla::ipc::TaskFactory<GPUProcessHost> mTaskFactory;
 
   enum class LaunchPhase {
     Unlaunched,
     Waiting,
     Complete
   };
   LaunchPhase mLaunchPhase;
 
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -94,20 +94,20 @@ public:
     LayerManager* aLayerManager,
     CSSToLayoutDeviceScale aScale,
     const CompositorOptions& aOptions,
     bool aUseExternalSurfaceSize,
     const gfx::IntSize& aSurfaceSize);
 
   bool CreateContentBridges(
     base::ProcessId aOtherProcess,
-    ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
-    ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
-    ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
-    ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
+    mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
+    mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
+    mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
+    mozilla::ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
     nsTArray<uint32_t>* aNamespaces);
 
   // This returns a reference to the APZCTreeManager to which
   // pan/zoom-related events can be sent.
   already_AddRefed<IAPZCTreeManager> GetAPZCTreeManagerForLayers(uint64_t aLayersId);
 
   // Maps the layer tree and process together so that aOwningPID is allowed
   // to access aLayersId across process.
@@ -180,23 +180,23 @@ public:
     return mNumProcessAttempts > 0;
   }
 
 private:
   // Called from our xpcom-shutdown observer.
   void OnXPCOMShutdown();
 
   bool CreateContentCompositorManager(base::ProcessId aOtherProcess,
-                                      ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
+                                      mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
   bool CreateContentImageBridge(base::ProcessId aOtherProcess,
-                                ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
+                                mozilla::ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
   bool CreateContentVRManager(base::ProcessId aOtherProcess,
-                              ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
+                              mozilla::ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
   void CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
-                                        ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
+                                        mozilla::ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
 
   // Called from RemoteCompositorSession. We track remote sessions so we can
   // notify their owning widgets that the session must be restarted.
   void RegisterRemoteProcessSession(RemoteCompositorSession* aSession);
   void UnregisterRemoteProcessSession(RemoteCompositorSession* aSession);
 
   // Called from InProcessCompositorSession. We track in process sessino so we can
   // notify their owning widgets that the session must be restarted
@@ -253,17 +253,17 @@ private:
     GPUProcessManager* mManager;
   };
   friend class Observer;
 
 private:
   bool mDecodeVideoOnGpuProcess = true;
 
   RefPtr<Observer> mObserver;
-  ipc::TaskFactory<GPUProcessManager> mTaskFactory;
+  mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory;
   RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
   uint32_t mNextNamespace;
   uint32_t mIdNamespace;
   uint32_t mResourceId;
   uint32_t mNumProcessAttempts;
 
   nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
   nsTArray<RefPtr<InProcessCompositorSession>> mInProcessSessions;
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -1,28 +1,31 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* 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 "mozilla/ContentCache.h"
+
 #include "mozilla/IMEStateManager.h"
+#include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Logging.h"
+#include "mozilla/Move.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/SizePrintfMacros.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
+#include "mozilla/dom/TabParent.h"
 #include "nsIWidget.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/Move.h"
-#include "mozilla/IntegerPrintfMacros.h"
-#include "mozilla/SizePrintfMacros.h"
 
 namespace mozilla {
 
+using namespace dom;
 using namespace widget;
 
 static const char*
 GetBoolName(bool aBool)
 {
   return aBool ? "true" : "false";
 }
 
@@ -506,18 +509,19 @@ ContentCacheInChild::SetSelection(nsIWid
   }
   Unused << NS_WARN_IF(!CacheTextRects(aWidget));
 }
 
 /*****************************************************************************
  * mozilla::ContentCacheInParent
  *****************************************************************************/
 
-ContentCacheInParent::ContentCacheInParent()
+ContentCacheInParent::ContentCacheInParent(TabParent& aTabParent)
   : ContentCache()
+  , mTabParent(aTabParent)
   , mCommitStringByRequest(nullptr)
   , mPendingEventsNeedingAck(0)
   , mCompositionStartInChild(UINT32_MAX)
   , mPendingCompositionCount(0)
   , mWidgetHasComposition(false)
 {
 }
 
@@ -1229,16 +1233,20 @@ ContentCacheInParent::RequestIMEToCommit
     MOZ_LOG(sContentCacheLog, LogLevel::Warning,
       ("  0x%p RequestToCommitComposition(), "
        "does nothing due to no composition", this));
     return false;
   }
 
   mCommitStringByRequest = &aCommittedString;
 
+  // TODO: This request may be too late.  For example, while the remote process
+  //       was busy, focus may be already changed to the main process and the
+  //       composition has already been canceled by IMEStateManager.  So, this
+  //       should check if IME focus is in the TabParent.
   aWidget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
                                                REQUEST_TO_COMMIT_COMPOSITION));
 
   mCommitStringByRequest = nullptr;
 
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("  0x%p RequestToCommitComposition(), "
      "mWidgetHasComposition=%s, the composition %s committed synchronously",
@@ -1269,17 +1277,17 @@ ContentCacheInParent::RequestIMEToCommit
   return true;
 }
 
 void
 ContentCacheInParent::MaybeNotifyIME(nsIWidget* aWidget,
                                      const IMENotification& aNotification)
 {
   if (!mPendingEventsNeedingAck) {
-    IMEStateManager::NotifyIME(aNotification, aWidget, true);
+    IMEStateManager::NotifyIME(aNotification, aWidget, &mTabParent);
     return;
   }
 
   switch (aNotification.mMessage) {
     case NOTIFY_IME_OF_SELECTION_CHANGE:
       mPendingSelectionChange.MergeWith(aNotification);
       break;
     case NOTIFY_IME_OF_TEXT_CHANGE:
@@ -1310,45 +1318,45 @@ ContentCacheInParent::FlushPendingNotifi
 
   // First, text change notification should be sent because selection change
   // notification notifies IME of current selection range in the latest content.
   // So, IME may need the latest content before that.
   if (mPendingTextChange.HasNotification()) {
     IMENotification notification(mPendingTextChange);
     if (!aWidget->Destroyed()) {
       mPendingTextChange.Clear();
-      IMEStateManager::NotifyIME(notification, aWidget, true);
+      IMEStateManager::NotifyIME(notification, aWidget, &mTabParent);
     }
   }
 
   if (mPendingSelectionChange.HasNotification()) {
     IMENotification notification(mPendingSelectionChange);
     if (!aWidget->Destroyed()) {
       mPendingSelectionChange.Clear();
-      IMEStateManager::NotifyIME(notification, aWidget, true);
+      IMEStateManager::NotifyIME(notification, aWidget, &mTabParent);
     }
   }
 
   // Layout change notification should be notified after selection change
   // notification because IME may want to query position of new caret position.
   if (mPendingLayoutChange.HasNotification()) {
     IMENotification notification(mPendingLayoutChange);
     if (!aWidget->Destroyed()) {
       mPendingLayoutChange.Clear();
-      IMEStateManager::NotifyIME(notification, aWidget, true);
+      IMEStateManager::NotifyIME(notification, aWidget, &mTabParent);
     }
   }
 
   // Finally, send composition update notification because it notifies IME of
   // finishing handling whole sending events.
   if (mPendingCompositionUpdate.HasNotification()) {
     IMENotification notification(mPendingCompositionUpdate);
     if (!aWidget->Destroyed()) {
       mPendingCompositionUpdate.Clear();
-      IMEStateManager::NotifyIME(notification, aWidget, true);
+      IMEStateManager::NotifyIME(notification, aWidget, &mTabParent);
     }
   }
 
   if (!--mPendingEventsNeedingAck && !aWidget->Destroyed() &&
       (mPendingTextChange.HasNotification() ||
        mPendingSelectionChange.HasNotification() ||
        mPendingLayoutChange.HasNotification() ||
        mPendingCompositionUpdate.HasNotification())) {
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -18,16 +18,20 @@
 #include "nsString.h"
 #include "nsTArray.h"
 #include "Units.h"
 
 namespace mozilla {
 
 class ContentCacheInParent;
 
+namespace dom {
+class TabParent;
+} // namespace dom
+
 /**
  * ContentCache stores various information of the child content.
  * This class has members which are necessary both in parent process and
  * content process.
  */
 
 class ContentCache
 {
@@ -313,17 +317,17 @@ private:
                   const IMENotification* aNotification = nullptr);
   bool CacheTextRects(nsIWidget* aWidget,
                       const IMENotification* aNotification = nullptr);
 };
 
 class ContentCacheInParent final : public ContentCache
 {
 public:
-  ContentCacheInParent();
+  explicit ContentCacheInParent(dom::TabParent& aTabParent);
 
   /**
    * AssignContent() is called when TabParent receives ContentCache from
    * the content process.  This doesn't copy composition information because
    * it's managed by TabParent itself.
    */
   void AssignContent(const ContentCache& aOther,
                      nsIWidget* aWidget,
@@ -401,16 +405,18 @@ public:
                       const IMENotification& aNotification);
 
 private:
   IMENotification mPendingSelectionChange;
   IMENotification mPendingTextChange;
   IMENotification mPendingLayoutChange;
   IMENotification mPendingCompositionUpdate;
 
+  // mTabParent is owner of the instance.
+  dom::TabParent& MOZ_NON_OWNING_REF mTabParent;
   // This is not nullptr only while the instance is requesting IME to
   // composition.  Then, data value of dispatched composition events should
   // be stored into the instance.
   nsAString* mCommitStringByRequest;
   // mPendingEventsNeedingAck is increased before sending a composition event or
   // a selection event and decreased after they are received in the child
   // process.
   uint32_t mPendingEventsNeedingAck;
@@ -427,16 +433,18 @@ private:
   // mPendingCompositionCount is number of compositions which started in widget
   // but not yet handled in the child process.
   uint8_t mPendingCompositionCount;
   // mWidgetHasComposition is true when the widget in this process thinks that
   // IME has composition.  So, this is set to true when eCompositionStart is
   // dispatched and set to false when eCompositionCommit(AsIs) is dispatched.
   bool mWidgetHasComposition;
 
+  ContentCacheInParent() = delete;
+
   /**
    * When following methods' aRoundToExistingOffset is true, even if specified
    * offset or range is out of bounds, the result is computed with the existing
    * cache forcibly.
    */
   bool GetCaretRect(uint32_t aOffset,
                     bool aRoundToExistingOffset,
                     LayoutDeviceIntRect& aCaretRect) const;
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -393,18 +393,19 @@ IMEHandler::GetOpenState(nsWindow* aWind
 void
 IMEHandler::OnDestroyWindow(nsWindow* aWindow)
 {
   // When focus is in remote process, but the window is being destroyed, we
   // need to clean up TSFTextStore here since NOTIFY_IME_OF_BLUR won't reach
   // here because TabParent already lost the reference to the nsWindow when
   // it receives from the remote process.
   if (sFocusedWindow == aWindow) {
-    NS_ASSERTION(aWindow->GetInputContext().IsOriginContentProcess(),
-      "input context of focused widget should be set from a remote process");
+    MOZ_ASSERT(aWindow->GetInputContext().IsOriginContentProcess(),
+      "input context of focused widget should've been set by a remote process "
+      "if IME focus isn't cleared before destroying the widget");
     NotifyIME(aWindow, IMENotification(NOTIFY_IME_OF_BLUR));
   }
 
 #ifdef NS_ENABLE_TSF
   // We need to do nothing here for TSF. Just restore the default context
   // if it's been disassociated.
   if (!sIsInTSFMode) {
     // MSDN says we need to set IS_DEFAULT to avoid memory leak when we use