Bug 1137572 part.3 Use pseudo IME context when TextEventDispatcher has input transaction which is not for native event handler r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 16 Mar 2016 13:47:47 +0900
changeset 288885 a8dbb4e58e546843c0b0710f8aa2b453f5cfcadc
parent 288884 b8af9e4c043927f01a858538b0d7e46b6e5c25b0
child 288886 06d5532f051f5a0c6796443d0c1794700c6667b6
push id73609
push usermasayuki@d-toybox.com
push dateWed, 16 Mar 2016 04:47:58 +0000
treeherdermozilla-inbound@eb7c36e2ef5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1137572
milestone48.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 1137572 part.3 Use pseudo IME context when TextEventDispatcher has input transaction which is not for native event handler r=smaug
widget/TextEventDispatcher.cpp
widget/TextEventDispatcher.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/nsBaseWidget.h
widget/qt/nsWindow.cpp
widget/uikit/nsWindow.mm
widget/windows/nsWindow.cpp
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -150,24 +150,29 @@ TextEventDispatcher::InitEvent(WidgetGUI
 {
   aEvent.time = PR_IntervalNow();
   aEvent.refPoint = LayoutDeviceIntPoint(0, 0);
   aEvent.mFlags.mIsSynthesizedForTests =
     mInputTransactionType == eTestInputTransaction;
   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);
+  void* pseudoIMEContext = GetPseudoIMEContext();
+  if (pseudoIMEContext) {
+    aEvent.AsCompositionEvent()->mNativeIMEContext.
+      InitWithRawNativeIMEContext(pseudoIMEContext);
   }
+#ifdef DEBUG
+  else {
+    MOZ_ASSERT(!XRE_IsContentProcess(),
+      "Why did the content process start native event transaction?");
+    MOZ_ASSERT(aEvent.AsCompositionEvent()->mNativeIMEContext.IsValid(),
+      "Native IME context shouldn't be invalid");
+  }
+#endif // #ifdef DEBUG
 }
 
 nsresult
 TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
                                    WidgetGUIEvent& aEvent,
                                    nsEventStatus& aStatus)
 {
   MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()");
--- a/widget/TextEventDispatcher.h
+++ b/widget/TextEventDispatcher.h
@@ -93,16 +93,30 @@ public:
   bool IsComposing() const { return mIsComposing; }
 
   /**
    * IsDispatchingEvent() returns true while this instance dispatching an event.
    */
   bool IsDispatchingEvent() const { return mDispatchingEvent > 0; }
 
   /**
+   * GetPseudoIMEContext() returns pseudo native IME context if there is an
+   * input transaction whose type is not for native event handler.
+   * Otherwise, returns nullptr.
+   */
+  void* GetPseudoIMEContext() const
+  {
+    if (mInputTransactionType == eNoInputTransaction ||
+        mInputTransactionType == eNativeInputTransaction) {
+      return nullptr;
+    }
+    return const_cast<TextEventDispatcher*>(this);
+  }
+
+  /**
    * StartComposition() starts composition explicitly.
    */
   nsresult StartComposition(nsEventStatus& aStatus);
 
   /**
    * CommitComposition() commits composition.
    *
    * @param aCommitString   If this is null, commits with the last composition
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1983,19 +1983,24 @@ 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_RAW_NATIVE_IME_CONTEXT:
+        case NS_RAW_NATIVE_IME_CONTEXT: {
+            void* pseudoIMEContext = GetPseudoIMEContext();
+            if (pseudoIMEContext) {
+                return pseudoIMEContext;
+            }
             // We assume that there is only one context per process on Android
             return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+        }
 
         case NS_NATIVE_NEW_EGL_SURFACE:
             if (!mGLControllerSupport) {
                 return nullptr;
             }
             return static_cast<void*>(mGLControllerSupport->CreateEGLSurface());
     }
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -684,16 +684,20 @@ void* nsChildView::GetNativeData(uint32_
       retVal = 0;
       break;
 
     case NS_NATIVE_OFFSETY:
       retVal = 0;
       break;
 
     case NS_RAW_NATIVE_IME_CONTEXT:
+      retVal = GetPseudoIMEContext();
+      if (retVal) {
+        break;
+      }
       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
@@ -591,16 +591,20 @@ void* nsCocoaWindow::GetNativeData(uint3
       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_RAW_NATIVE_IME_CONTEXT: {
+      retVal = GetPseudoIMEContext();
+      if (retVal) {
+        break;
+      }
       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
@@ -531,20 +531,25 @@ 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_RAW_NATIVE_IME_CONTEXT:
+    case NS_RAW_NATIVE_IME_CONTEXT: {
+        void* pseudoIMEContext = GetPseudoIMEContext();
+        if (pseudoIMEContext) {
+            return pseudoIMEContext;
+        }
         // 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)
 {
     switch (aDataType) {
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1735,25 +1735,28 @@ 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_RAW_NATIVE_IME_CONTEXT:
+    case NS_RAW_NATIVE_IME_CONTEXT: {
+        void* pseudoIMEContext = GetPseudoIMEContext();
+        if (pseudoIMEContext) {
+            return pseudoIMEContext;
+        }
         // 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)) {
+        // instead of nullptr.
+        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)
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1782,16 +1782,26 @@ nsBaseWidget::EnsureTextEventDispatcher(
 
 NS_IMETHODIMP_(nsIWidget::TextEventDispatcher*)
 nsBaseWidget::GetTextEventDispatcher()
 {
   EnsureTextEventDispatcher();
   return mTextEventDispatcher;
 }
 
+void*
+nsBaseWidget::GetPseudoIMEContext()
+{
+  TextEventDispatcher* dispatcher = GetTextEventDispatcher();
+  if (!dispatcher) {
+    return nullptr;
+  }
+  return dispatcher->GetPseudoIMEContext();
+}
+
 NS_IMETHODIMP_(TextEventDispatcherListener*)
 nsBaseWidget::GetNativeTextEventDispatcherListener()
 {
   // TODO: If all platforms supported use of TextEventDispatcher for handling
   //       native IME and keyboard events, this method should be removed since
   //       in such case, this is overridden by all the subclasses.
   return nullptr;
 }
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -426,16 +426,22 @@ protected:
   {
     mozilla::widget::AutoObserverNotifier notifier(aObserver, "touchpoint");
     return NS_ERROR_UNEXPECTED;
   }
 
   virtual nsresult NotifyIMEInternal(const IMENotification& aIMENotification)
   { return NS_ERROR_NOT_IMPLEMENTED; }
 
+  /**
+   * GetPseudoIMEContext() returns pseudo IME context when TextEventDispatcher
+   * has non-native input transaction.  Otherwise, returns nullptr.
+   */
+  void* GetPseudoIMEContext();
+
 protected:
   // Utility to check if an array of clip rects is equal to our
   // internally stored clip rect array mClipRects.
   bool IsWindowClipRegionEqual(const nsTArray<LayoutDeviceIntRect>& aRects);
 
   // Stores the clip rectangles in aRects into mClipRects.
   void StoreWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects);
 
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -655,20 +655,25 @@ nsWindow::GetNativeData(uint32_t aDataTy
 #endif
         break;
     }
     case NS_NATIVE_PLUGIN_PORT:
     case NS_NATIVE_GRAPHIC:
     case NS_NATIVE_SHELLWIDGET: {
         break;
     }
-    case NS_RAW_NATIVE_IME_CONTEXT:
+    case NS_RAW_NATIVE_IME_CONTEXT: {
+        void* pseudoIMEContext = GetPseudoIMEContext();
+        if (pseudoIMEContext) {
+            return pseudoIMEContext;
+        }
         // 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;
 }
 
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -870,16 +870,20 @@ void* nsWindow::GetNativeData(uint32_t a
       retVal = 0;
       break;
 
     case NS_NATIVE_PLUGIN_PORT:
         // not implemented
         break;
 
     case NS_RAW_NATIVE_IME_CONTEXT:
+      retVal = GetPseudoIMEContext();
+      if (retVal) {
+        break;
+      }
       retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
       break;
   }
 
   return retVal;
 }
 
 CGFloat
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3239,17 +3239,23 @@ 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_RAW_NATIVE_IME_CONTEXT:
+    case NS_RAW_NATIVE_IME_CONTEXT: {
+      void* pseudoIMEContext = GetPseudoIMEContext();
+      if (pseudoIMEContext) {
+        return pseudoIMEContext;
+      }
+      MOZ_FALLTHROUGH;
+    }
     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;
   }