Bug 1179632 part.2 WidgetCompositionEvent should store NativeIMEContext which caused the event and PuppetWidget should store it for GetNativeIMEContext() r=smaug, sr=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 11 Dec 2015 15:15:57 +0900
changeset 312146 63101b99fa95195574c9eab5680b1f1acd4442ba
parent 312145 a58871d438cc47cc9e5b835b969ca27084cbbae4
child 312147 d285dc8f2ed559cbddfeae63117a66a7e466e6d0
push id1040
push userraliiev@mozilla.com
push dateMon, 29 Feb 2016 17:11:22 +0000
treeherdermozilla-release@8c3167321162 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, smaug
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.2 WidgetCompositionEvent should store NativeIMEContext which caused the event and PuppetWidget should store it for GetNativeIMEContext() r=smaug, sr=smaug
dom/events/IMEStateManager.cpp
dom/events/TextComposition.cpp
dom/events/TextComposition.h
widget/IMEData.h
widget/PuppetWidget.cpp
widget/PuppetWidget.h
widget/TextEventDispatcher.cpp
widget/TextEvents.h
widget/android/nsWindow.cpp
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.mm
widget/gonk/nsWindow.cpp
widget/gtk/nsWindow.cpp
widget/nsBaseWidget.cpp
widget/nsGUIEventIPC.h
widget/nsIWidget.h
widget/qt/nsWindow.cpp
widget/uikit/nsWindow.mm
widget/windows/WinIMEHandler.cpp
widget/windows/nsWindow.cpp
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1132,21 +1132,31 @@ IMEStateManager::DispatchCompositionEven
                    bool aIsSynthesized)
 {
   RefPtr<TabParent> tabParent =
     aEventTargetNode->IsContent() ?
       TabParent::GetFrom(aEventTargetNode->AsContent()) : nullptr;
 
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
-     "aPresContext=0x%p, aCompositionEvent={ message=%s, "
+     "aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
+     "mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, widget(0x%p)={ "
+     "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, Destroyed()=%s }, "
      "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
      "aIsSynthesized=%s), tabParent=%p",
      aEventTargetNode, aPresContext,
      ToChar(aCompositionEvent->mMessage),
+     aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
+     aCompositionEvent->mNativeIMEContext.mOriginProcessID,
+     aCompositionEvent->widget.get(),
+     aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
+     aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
+     GetBoolName(aCompositionEvent->widget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
      GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
      GetBoolName(aIsSynthesized), tabParent.get()));
 
   if (!aCompositionEvent->mFlags.mIsTrusted ||
       aCompositionEvent->mFlags.mPropagationStopped) {
     return;
   }
@@ -1266,18 +1276,28 @@ void
 IMEStateManager::OnCompositionEventDiscarded(
                    WidgetCompositionEvent* aCompositionEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
 
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ "
-     "mMessage=%s, mFlags={ mIsTrusted=%s } })",
+     "mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, widget(0x%p)={ "
+     "GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
+     "mOriginProcessID=0x%X }, Destroyed()=%s }, "
+     "mFlags={ mIsTrusted=%s } })",
      ToChar(aCompositionEvent->mMessage),
+     aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
+     aCompositionEvent->mNativeIMEContext.mOriginProcessID,
+     aCompositionEvent->widget.get(),
+     aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
+     aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
+     GetBoolName(aCompositionEvent->widget->Destroyed()),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
 
   if (!aCompositionEvent->mFlags.mIsTrusted) {
     return;
   }
 
   // Ignore compositionstart for now because sTextCompositions may not have
   // been created yet.
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -34,50 +34,44 @@ bool TextComposition::sHandlingSelection
 
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
                                  TabParent* aTabParent,
                                  WidgetCompositionEvent* aCompositionEvent)
   : mPresContext(aPresContext)
   , mNode(aNode)
   , mTabParent(aTabParent)
-  , mNativeContext(
-      aCompositionEvent->widget->GetNativeData(NS_NATIVE_IME_CONTEXT))
+  , mNativeContext(aCompositionEvent->mNativeIMEContext)
   , mCompositionStartOffset(0)
   , mCompositionTargetOffset(0)
   , mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
   , mIsComposing(false)
   , mIsEditorHandlingEvent(false)
   , mIsRequestingCommit(false)
   , mIsRequestingCancel(false)
   , mRequestedToCommitOrCancel(false)
   , mWasNativeCompositionEndEventDiscarded(false)
   , mAllowControlCharacters(
       Preferences::GetBool("dom.compositionevent.allow_control_characters",
                            false))
 {
+  MOZ_ASSERT(aCompositionEvent->mNativeIMEContext.IsValid());
 }
 
 void
 TextComposition::Destroy()
 {
   mPresContext = nullptr;
   mNode = nullptr;
   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->GetNativeData(NS_NATIVE_IME_CONTEXT);
-}
-
-bool
 TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const
 {
   return !Destroyed() && aWidget && !aWidget->Destroyed() &&
          mPresContext->GetPresShell() &&
          !mPresContext->GetPresShell()->IsDestroying();
 }
 
 bool
@@ -109,16 +103,17 @@ TextComposition::CloneAndDispatchAs(
   MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
              "Should be called only when it's safe to dispatch an event");
 
   WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
                                           aMessage, aCompositionEvent->widget);
   compositionEvent.time = aCompositionEvent->time;
   compositionEvent.timeStamp = aCompositionEvent->timeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
+  compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
   compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
   compositionEvent.mFlags.mIsSynthesizedForTests =
     aCompositionEvent->mFlags.mIsSynthesizedForTests;
 
   nsEventStatus dummyStatus = nsEventStatus_eConsumeNoDefault;
   nsEventStatus* status = aStatus ? aStatus : &dummyStatus;
   if (aMessage == eCompositionUpdate) {
     mLastData = compositionEvent.mData;
@@ -608,32 +603,34 @@ TextComposition::CompositionEventDispatc
     return NS_OK; // cannot dispatch any events anymore
   }
 
   RefPtr<nsPresContext> presContext = mTextComposition->mPresContext;
   nsEventStatus status = nsEventStatus_eIgnore;
   switch (mEventMessage) {
     case eCompositionStart: {
       WidgetCompositionEvent compStart(true, eCompositionStart, widget);
+      compStart.mNativeIMEContext = mTextComposition->mNativeContext;
       WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
       ContentEventHandler handler(presContext);
       handler.OnQuerySelectedText(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compStart.mData = selectedText.mReply.mString;
       compStart.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compStart, &status, nullptr,
                                                 mIsSynthesizedEvent);
       break;
     }
     case eCompositionChange:
     case eCompositionCommitAsIs:
     case eCompositionCommit: {
       WidgetCompositionEvent compEvent(true, mEventMessage, widget);
+      compEvent.mNativeIMEContext = mTextComposition->mNativeContext;
       if (mEventMessage != eCompositionCommitAsIs) {
         compEvent.mData = mData;
       }
       compEvent.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compEvent, &status, nullptr,
                                                 mIsSynthesizedEvent);
@@ -645,27 +642,36 @@ TextComposition::CompositionEventDispatc
   return NS_OK;
 }
 
 /******************************************************************************
  * TextCompositionArray
  ******************************************************************************/
 
 TextCompositionArray::index_type
-TextCompositionArray::IndexOf(nsIWidget* aWidget)
+TextCompositionArray::IndexOf(const NativeIMEContext& aNativeIMEContext)
 {
+  if (!aNativeIMEContext.IsValid()) {
+    return NoIndex;
+  }
   for (index_type i = Length(); i > 0; --i) {
-    if (ElementAt(i - 1)->MatchesNativeContext(aWidget)) {
+    if (ElementAt(i - 1)->GetNativeIMEContext() == aNativeIMEContext) {
       return i - 1;
     }
   }
   return NoIndex;
 }
 
 TextCompositionArray::index_type
+TextCompositionArray::IndexOf(nsIWidget* aWidget)
+{
+  return IndexOf(aWidget->GetNativeIMEContext());
+}
+
+TextCompositionArray::index_type
 TextCompositionArray::IndexOf(nsPresContext* aPresContext)
 {
   for (index_type i = Length(); i > 0; --i) {
     if (ElementAt(i - 1)->GetPresContext() == aPresContext) {
       return i - 1;
     }
   }
   return NoIndex;
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -71,17 +71,20 @@ public:
   nsIWidget* GetWidget() const
   {
     return mPresContext ? mPresContext->GetRootWidget() : nullptr;
   }
   // Returns true if the composition is started with synthesized event which
   // came from nsDOMWindowUtils.
   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
 
-  bool MatchesNativeContext(nsIWidget* aWidget) const;
+  const widget::NativeIMEContext& GetNativeIMEContext() const
+  {
+    return mNativeContext;
+  }
 
   /**
    * This is called when IMEStateManager stops managing the instance.
    */
   void Destroy();
 
   /**
    * Request to commit (or cancel) the composition to IME.  This method should
@@ -186,17 +189,17 @@ private:
   RefPtr<TabParent> mTabParent;
 
   // This is the clause and caret range information which is managed by
   // the focused editor.  This may be null if there is no clauses or caret.
   RefPtr<TextRangeArray> mRanges;
 
   // mNativeContext stores a opaque pointer.  This works as the "ID" for this
   // composition.  Don't access the instance, it may not be available.
-  void* mNativeContext;
+  widget::NativeIMEContext mNativeContext;
 
   // mEditorWeak is a weak reference to the focused editor handling composition.
   nsWeakPtr mEditorWeak;
 
   // mLastData stores the data attribute of the latest composition event (except
   // the compositionstart event).
   nsString mLastData;
 
@@ -395,16 +398,17 @@ private:
  * compositions in the process.  If the instance is it, each TextComposition
  * in the array can be destroyed by calling some methods of itself.
  */
 
 class TextCompositionArray final :
   public nsAutoTArray<RefPtr<TextComposition>, 2>
 {
 public:
+  index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
   index_type IndexOf(nsIWidget* aWidget);
   index_type IndexOf(nsPresContext* aPresContext);
   index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
 
   TextComposition* GetCompositionFor(nsIWidget* aWidget);
   TextComposition* GetCompositionFor(nsPresContext* aPresContext,
                                      nsINode* aNode);
   TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -5,16 +5,18 @@
 
 #ifndef mozilla_widget_IMEData_h_
 #define mozilla_widget_IMEData_h_
 
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsStringGlue.h"
 
+class nsIWidget;
+
 namespace mozilla {
 
 class WritingMode;
 
 } // namespace mozilla
 
 /**
  * Preference for receiving IME updates
@@ -223,16 +225,59 @@ struct IMEState final
   }
 };
 
 // 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 NativeIMEContext final
+{
+  // Pointer to native IME context.  Typically this is the result of
+  // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process.
+  // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
+  uintptr_t mRawNativeIMEContext;
+  // Process ID of the origin of mNativeIMEContext.
+  uint64_t mOriginProcessID;
+
+  NativeIMEContext()
+  {
+    Init(nullptr);
+  }
+
+  explicit NativeIMEContext(nsIWidget* aWidget)
+  {
+    Init(aWidget);
+  }
+
+  bool IsValid() const
+  {
+    return mRawNativeIMEContext &&
+           mOriginProcessID != static_cast<uintptr_t>(-1);
+  }
+
+  void Init(nsIWidget* aWidget);
+  void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext)
+  {
+    InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext));
+  }
+  void InitWithRawNativeIMEContext(void* aRawNativeIMEContext);
+
+  bool operator==(const NativeIMEContext& aOther) const
+  {
+    return mRawNativeIMEContext == aOther.mRawNativeIMEContext &&
+           mOriginProcessID == aOther.mOriginProcessID;
+  }
+  bool operator!=(const NativeIMEContext& aOther) const
+  {
+    return !(*this == aOther);
+  }
+};
+
 struct InputContext final
 {
   InputContext()
     : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
     , mMayBeIMEUnaware(false)
   {
   }
 
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -74,19 +74,19 @@ const size_t PuppetWidget::kMaxDimension
 
 NS_IMPL_ISUPPORTS_INHERITED0(PuppetWidget, nsBaseWidget)
 
 PuppetWidget::PuppetWidget(TabChild* aTabChild)
   : mTabChild(aTabChild)
   , mMemoryPressureObserver(nullptr)
   , mDPI(-1)
   , mDefaultScale(-1)
-  , mNativeKeyCommandsValid(false)
   , mCursorHotspotX(0)
   , mCursorHotspotY(0)
+  , mNativeKeyCommandsValid(false)
 {
   MOZ_COUNT_CTOR(PuppetWidget);
 
   mSingleLineCommands.SetCapacity(4);
   mMultiLineCommands.SetCapacity(4);
   mRichTextCommands.SetCapacity(4);
 }
 
@@ -314,16 +314,34 @@ PuppetWidget::DispatchEvent(WidgetGUIEve
   AutoCacheNativeKeyCommands autoCache(this);
   if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) {
     WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
     if (keyEvent) {
       mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent);
     }
   }
 
+  if (event->mClass == eCompositionEventClass) {
+    // Store the latest native IME context of parent process's widget or
+    // TextEventDispatcher if it's in this process.
+    WidgetCompositionEvent* compositionEvent = event->AsCompositionEvent();
+#ifdef DEBUG
+    if (mNativeIMEContext.IsValid() &&
+        mNativeIMEContext != compositionEvent->mNativeIMEContext) {
+      RefPtr<TextComposition> composition =
+        IMEStateManager::GetTextCompositionFor(this);
+      MOZ_ASSERT(!composition,
+        "When there is composition caused by old native IME context, "
+        "composition events caused by different native IME context are not "
+        "allowed");
+    }
+#endif // #ifdef DEBUG
+    mNativeIMEContext = compositionEvent->mNativeIMEContext;
+  }
+
   aStatus = nsEventStatus_eIgnore;
 
   if (GetCurrentWidgetListener()) {
     aStatus = GetCurrentWidgetListener()->HandleEvent(event, mUseAttachedEvents);
   }
 
   return NS_OK;
 }
@@ -569,16 +587,21 @@ PuppetWidget::GetLayerManager(PLayerTran
 
 nsresult
 PuppetWidget::IMEEndComposition(bool aCancel)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
+  // There must not be composition which is caused by the PuppetWidget instance.
+  if (NS_WARN_IF(!mNativeIMEContext.IsValid())) {
+    return NS_OK;
+  }
+
   nsEventStatus status;
   bool noCompositionEvent = true;
   WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
   InitEvent(compositionCommitEvent, nullptr);
   // SendEndIMEComposition is always called since ResetInputState
   // should always be called even if we aren't composing something.
   if (!mTabChild ||
       !mTabChild->SendEndIMEComposition(aCancel, &noCompositionEvent,
@@ -678,16 +701,22 @@ PuppetWidget::GetInputContext()
     // 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);
   }
   return context;
 }
 
+NS_IMETHODIMP_(NativeIMEContext)
+PuppetWidget::GetNativeIMEContext()
+{
+  return mNativeIMEContext;
+}
+
 nsresult
 PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
 {
 #ifndef MOZ_CROSS_PROCESS_IME
   return NS_OK;
 #endif
 
   if (!mTabChild)
@@ -1115,19 +1144,18 @@ 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_RAW_NATIVE_IME_CONTEXT:
+    MOZ_CRASH("You need to call GetNativeIMEContext() instead");
   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/PuppetWidget.h
+++ b/widget/PuppetWidget.h
@@ -174,16 +174,17 @@ public:
   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                   LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                   bool* aAllowRetaining = nullptr) override;
 
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction) override;
   NS_IMETHOD_(InputContext) GetInputContext() override;
+  NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext() override;
   virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
 
   NS_IMETHOD SetCursor(nsCursor aCursor) override;
   NS_IMETHOD SetCursor(imgIContainer* aCursor,
                        uint32_t aHotspotX, uint32_t aHotspotY) override;
 
   virtual void ClearCachedCursor() override;
 
@@ -249,19 +250,16 @@ public:
   virtual nsresult SynthesizeNativeTouchTap(ScreenIntPoint aPointerScreenPoint,
                                             bool aLongTap,
                                             nsIObserver* aObserver) override;
   virtual nsresult ClearNativeTouchSequence(nsIObserver* aObserver) override;
   virtual uint32_t GetMaxTouchPoints() const override;
 
   virtual void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
 protected:
-  bool mEnabled;
-  bool mVisible;
-
   virtual nsresult NotifyIMEInternal(
                      const IMENotification& aIMENotification) override;
 
 private:
   nsresult Paint();
 
   void SetChild(PuppetWidget* aChild);
 
@@ -317,31 +315,43 @@ private:
   nsRevocableEventPtr<PaintTask> mPaintTask;
   RefPtr<MemoryPressureObserver> mMemoryPressureObserver;
   // XXX/cjones: keeping this around until we teach LayerManager to do
   // retained-content-only transactions
   RefPtr<DrawTarget> mDrawTarget;
   // IME
   nsIMEUpdatePreference mIMEPreferenceOfParent;
   InputContext mInputContext;
+  // mNativeIMEContext is initialized when this dispatches every composition
+  // event both from parent process's widget and TextEventDispatcher in same
+  // process.  If it hasn't been started composition yet, this isn't necessary
+  // for XP code since there is no TextComposition instance which is caused by
+  // the PuppetWidget instance.
+  NativeIMEContext mNativeIMEContext;
   ContentCacheInChild mContentCache;
-  bool mNeedIMEStateInit;
 
   // The DPI of the screen corresponding to this widget
   float mDPI;
   double mDefaultScale;
 
   // Precomputed answers for ExecuteNativeKeyBinding
-  bool mNativeKeyCommandsValid;
   InfallibleTArray<mozilla::CommandInt> mSingleLineCommands;
   InfallibleTArray<mozilla::CommandInt> mMultiLineCommands;
   InfallibleTArray<mozilla::CommandInt> mRichTextCommands;
 
   nsCOMPtr<imgIContainer> mCustomCursor;
   uint32_t mCursorHotspotX, mCursorHotspotY;
+
+protected:
+  bool mEnabled;
+  bool mVisible;
+
+private:
+  bool mNeedIMEStateInit;
+  bool mNativeKeyCommandsValid;
 };
 
 struct AutoCacheNativeKeyCommands
 {
   explicit AutoCacheNativeKeyCommands(PuppetWidget* aWidget)
     : mWidget(aWidget)
   {
     mSavedValid = mWidget->mNativeKeyCommandsValid;
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -129,16 +129,27 @@ TextEventDispatcher::GetState() const
 }
 
 void
 TextEventDispatcher::InitEvent(WidgetGUIEvent& aEvent) const
 {
   aEvent.time = PR_IntervalNow();
   aEvent.refPoint = LayoutDeviceIntPoint(0, 0);
   aEvent.mFlags.mIsSynthesizedForTests = mForTests;
+  if (aEvent.mClass != eCompositionEventClass) {
+    return;
+  }
+  // Currently, we should set special native IME context when composition
+  // events are dispatched from PuppetWidget since PuppetWidget may have not
+  // known actual native IME context yet and it caches native IME context
+  // when it dispatches every WidgetCompositionEvent.
+  if (XRE_IsContentProcess()) {
+    aEvent.AsCompositionEvent()->
+      mNativeIMEContext.InitWithRawNativeIMEContext(mWidget);
+  }
 }
 
 nsresult
 TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
                                    WidgetGUIEvent& aEvent,
                                    nsEventStatus& aStatus)
 {
   MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()");
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -361,16 +361,17 @@ public:
   virtual WidgetCompositionEvent* AsCompositionEvent() override
   {
     return this;
   }
 
   WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
                          nsIWidget* aWidget)
     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass)
+    , mNativeIMEContext(aWidget)
     , mOriginalMessage(eVoidEvent)
   {
     // XXX compositionstart is cancelable in draft of DOM3 Events.
     //     However, it doesn't make sense for us, we cannot cancel composition
     //     when we send compositionstart event.
     mFlags.mCancelable = false;
   }
 
@@ -388,16 +389,20 @@ public:
 
   // The composition string or the commit string.  If the instance is a
   // compositionstart event, this is initialized with selected text by
   // TextComposition automatically.
   nsString mData;
 
   RefPtr<TextRangeArray> mRanges;
 
+  // mNativeIMEContext stores the native IME context which causes the
+  // composition event.
+  widget::NativeIMEContext mNativeIMEContext;
+
   // If the instance is a clone of another event, mOriginalMessage stores
   // the another event's mMessage.
   EventMessage mOriginalMessage;
 
   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
                                   bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1259,17 +1259,17 @@ 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:
+        case NS_RAW_NATIVE_IME_CONTEXT:
             // We assume that there is only one context per process on Android
             return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
 
     }
 
     return nullptr;
 }
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -680,17 +680,17 @@ void* nsChildView::GetNativeData(uint32_
     case NS_NATIVE_OFFSETX:
       retVal = 0;
       break;
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
 
-    case NS_NATIVE_IME_CONTEXT:
+    case NS_RAW_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;
       }
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -587,17 +587,17 @@ 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: {
+    case NS_RAW_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.
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -534,17 +534,17 @@ 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:
+    case NS_RAW_NATIVE_IME_CONTEXT:
         // There is only one IME context on Gonk.
         return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
     }
 
     return nullptr;
 }
 
 void
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1732,17 +1732,17 @@ 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:
+    case NS_RAW_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();
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -48,16 +48,17 @@
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/VsyncDispatcher.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/ChromeProcessController.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/Services.h"
 #include "mozilla/Snprintf.h"
 #include "nsRefPtrHashtable.h"
 #include "TouchEvents.h"
 #include "WritingModes.h"
 #include "InputData.h"
@@ -81,16 +82,17 @@ static int32_t gNumWidgets;
 #endif
 
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList;
 #endif
 
 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
 
+using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::ipc;
 using namespace mozilla::widget;
 using namespace mozilla;
 using base::Thread;
 
 nsIContent* nsBaseWidget::mLastRollup = nullptr;
 // Global user preference for disabling native theme. Used
@@ -2074,20 +2076,60 @@ nsIWidget::SnapshotWidgetOnScreen()
                   gfx::Rect(gfx::Point(), gfx::Size(size)),
                   gfx::Rect(gfx::Point(), gfx::Size(size)),
                   gfx::DrawSurfaceOptions(gfx::Filter::POINT));
 
   forwarder->DestroySharedSurface(&surface);
   return dt->Snapshot();
 }
 
+NS_IMETHODIMP_(nsIWidget::NativeIMEContext)
+nsIWidget::GetNativeIMEContext()
+{
+  return NativeIMEContext(this);
+}
+
 namespace mozilla {
 namespace widget {
 
 void
+NativeIMEContext::Init(nsIWidget* aWidget)
+{
+  if (!aWidget) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
+    mOriginProcessID = static_cast<uint64_t>(-1);
+    return;
+  }
+  if (!XRE_IsContentProcess()) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(
+      aWidget->GetNativeData(NS_RAW_NATIVE_IME_CONTEXT));
+    mOriginProcessID = 0;
+    return;
+  }
+  // If this is created in a child process, aWidget is an instance of
+  // PuppetWidget which doesn't support NS_RAW_NATIVE_IME_CONTEXT.
+  // Instead of that PuppetWidget::GetNativeIMEContext() returns cached
+  // native IME context of the parent process.
+  *this = aWidget->GetNativeIMEContext();
+}
+
+void
+NativeIMEContext::InitWithRawNativeIMEContext(void* aRawNativeIMEContext)
+{
+  if (NS_WARN_IF(!aRawNativeIMEContext)) {
+    mRawNativeIMEContext = reinterpret_cast<uintptr_t>(nullptr);
+    mOriginProcessID = static_cast<uint64_t>(-1);
+    return;
+  }
+  mRawNativeIMEContext = reinterpret_cast<uintptr_t>(aRawNativeIMEContext);
+  mOriginProcessID =
+    XRE_IsContentProcess() ? ContentChild::GetSingleton()->GetID() : 0;
+}
+
+void
 IMENotification::TextChangeDataBase::MergeWith(
                    const IMENotification::TextChangeDataBase& aOther)
 {
   MOZ_ASSERT(aOther.IsValid(),
              "Merging data must store valid data");
   MOZ_ASSERT(aOther.mStartOffset <= aOther.mRemovedEndOffset,
              "end of removed text must be same or larger than start");
   MOZ_ASSERT(aOther.mStartOffset <= aOther.mAddedEndOffset,
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -539,29 +539,31 @@ template<>
 struct ParamTraits<mozilla::WidgetCompositionEvent>
 {
   typedef mozilla::WidgetCompositionEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
     WriteParam(aMsg, aParam.mData);
+    WriteParam(aMsg, aParam.mNativeIMEContext);
     bool hasRanges = !!aParam.mRanges;
     WriteParam(aMsg, hasRanges);
     if (hasRanges) {
       WriteParam(aMsg, *aParam.mRanges.get());
     }
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     bool hasRanges;
     if (!ReadParam(aMsg, aIter,
                    static_cast<mozilla::WidgetGUIEvent*>(aResult)) ||
         !ReadParam(aMsg, aIter, &aResult->mData) ||
+        !ReadParam(aMsg, aIter, &aResult->mNativeIMEContext) ||
         !ReadParam(aMsg, aIter, &hasRanges)) {
       return false;
     }
 
     if (!hasRanges) {
       aResult->mRanges = nullptr;
     } else {
       aResult->mRanges = new mozilla::TextRangeArray();
@@ -677,16 +679,34 @@ struct ParamTraits<nsIMEUpdatePreference
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mWantUpdates);
   }
 };
 
 template<>
+struct ParamTraits<mozilla::widget::NativeIMEContext>
+{
+  typedef mozilla::widget::NativeIMEContext paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mRawNativeIMEContext);
+    WriteParam(aMsg, aParam.mOriginProcessID);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mRawNativeIMEContext) &&
+           ReadParam(aMsg, aIter, &aResult->mOriginProcessID);
+  }
+};
+
+template<>
 struct ParamTraits<mozilla::widget::IMENotification::Point>
 {
   typedef mozilla::widget::IMENotification::Point paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mX);
     WriteParam(aMsg, aParam.mY);
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -100,21 +100,23 @@ typedef void* nsNativeWidget;
 // 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
-// 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
+// This is available only with GetNativeData() in parent process.  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.  Note that the result is only valid in the process.  So,
+// XP code should use nsIWidget::GetNativeIMEContext() instead of using this.
+#define NS_RAW_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
@@ -123,18 +125,18 @@ typedef void* nsNativeWidget;
 #define NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW 105
 #endif
 #if defined(MOZ_WIDGET_GTK)
 // set/get nsPluginNativeWindowGtk, e10s specific
 #define NS_NATIVE_PLUGIN_OBJECT_PTR    104
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0xd953b7a1, 0x6981, 0x4ed7, \
-  { 0xbc, 0xf0, 0xed, 0x96, 0x70, 0xee, 0x23, 0x28 } }
+{ 0xaaa79c8d, 0xc99d, 0x4fe1, \
+  { 0xa5, 0x11, 0xd3, 0xeb, 0xb1, 0x61, 0x9e, 0x26 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -329,16 +331,17 @@ class nsIWidget : public nsISupports {
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
     typedef mozilla::layers::ZoomConstraints ZoomConstraints;
     typedef mozilla::widget::IMEMessage IMEMessage;
     typedef mozilla::widget::IMENotification IMENotification;
     typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
+    typedef mozilla::widget::NativeIMEContext NativeIMEContext;
     typedef mozilla::widget::SizeConstraints SizeConstraints;
     typedef mozilla::widget::TextEventDispatcher TextEventDispatcher;
     typedef mozilla::CompositorVsyncDispatcher CompositorVsyncDispatcher;
     typedef mozilla::LayoutDeviceIntMargin LayoutDeviceIntMargin;
     typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
     typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
     typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
     typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
@@ -1791,16 +1794,23 @@ public:
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                       const InputContextAction& aAction) = 0;
 
     /*
      * Get current input context.
      */
     NS_IMETHOD_(InputContext) GetInputContext() = 0;
 
+    /**
+     * Get native IME context.  This is different from GetNativeData() with
+     * NS_RAW_NATIVE_IME_CONTEXT, the result is unique even if in a remote
+     * process.
+     */
+    NS_IMETHOD_(NativeIMEContext) GetNativeIMEContext();
+
     /*
      * Given a WidgetKeyboardEvent, this method synthesizes a corresponding
      * native (OS-level) event for it. This method allows tests to simulate
      * keystrokes that trigger native key bindings (which require a native
      * event).
      */
     NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) = 0;
 
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -659,17 +659,17 @@ 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:
+    case NS_RAW_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));
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -874,17 +874,17 @@ 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:
+    case NS_RAW_NATIVE_IME_CONTEXT:
       retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
       break;
   }
 
   return retVal;
 }
 
 CGFloat
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -91,17 +91,17 @@ IMEHandler::Terminate()
 
   IMMHandler::Terminate();
 }
 
 // static
 void*
 IMEHandler::GetNativeData(nsWindow* aWindow, uint32_t aDataType)
 {
-  if (aDataType == NS_NATIVE_IME_CONTEXT) {
+  if (aDataType == NS_RAW_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();
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3145,17 +3145,17 @@ 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_RAW_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(this, aDataType);
 
     default:
       break;
   }