Bug 749123 Don't use GtkIMContextSimple for IME disabled editor (GTK3 build) r=karlt
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 28 Jan 2014 18:02:08 +0900
changeset 165589 64bf5ddbf7544a3a58912921486d4da75d100e13
parent 165588 277e7626551fd7aae037712e1215c5eeae2cd141
child 165590 29a9828e695f4a1d1d102e255dcc574cf40e3d3f
push id4623
push userryanvm@gmail.com
push dateTue, 28 Jan 2014 21:48:39 +0000
treeherderfx-team@7e79536aca0a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs749123
milestone29.0a1
Bug 749123 Don't use GtkIMContextSimple for IME disabled editor (GTK3 build) r=karlt
modules/libpref/src/init/all.js
widget/gtk/nsGtkIMModule.cpp
widget/gtk/nsGtkIMModule.h
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3842,16 +3842,22 @@ pref("print.postscript.print_command", "
 // 2. The parent of non-topmost panel is not activated when the panel is hidden.
 // So, we have no reasons we should use non-toplevel window for popup.
 pref("ui.panel.default_level_parent", true);
 
 pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
 
 pref("ui.key.menuAccessKeyFocuses", true);
 
+#if MOZ_WIDGET_GTK == 2
+pref("intl.ime.use_simple_context_on_password_field", true);
+#else
+pref("intl.ime.use_simple_context_on_password_field", false);
+#endif
+
 # XP_UNIX
 #endif
 #endif
 #endif
 
 #if OS_ARCH==AIX
 
 // Override default Japanese fonts
--- a/widget/gtk/nsGtkIMModule.cpp
+++ b/widget/gtk/nsGtkIMModule.cpp
@@ -55,33 +55,44 @@ GetEnabledStateName(uint32_t aState)
         case IMEState::PLUGIN:
             return "PLUG_IN";
         default:
             return "UNKNOWN ENABLED STATUS!!";
     }
 }
 #endif
 
+const static bool kUseSimpleContextDefault = MOZ_WIDGET_GTK == 2;
+
 nsGtkIMModule* nsGtkIMModule::sLastFocusedModule = nullptr;
+bool nsGtkIMModule::sUseSimpleContext;
 
 nsGtkIMModule::nsGtkIMModule(nsWindow* aOwnerWindow) :
     mOwnerWindow(aOwnerWindow), mLastFocusedWindow(nullptr),
     mContext(nullptr),
     mSimpleContext(nullptr),
     mDummyContext(nullptr),
     mCompositionStart(UINT32_MAX), mProcessingKeyEvent(nullptr),
     mCompositionTargetOffset(UINT32_MAX),
     mCompositionState(eCompositionState_NotComposing),
     mIsIMFocused(false), mIgnoreNativeCompositionEvent(false)
 {
 #ifdef PR_LOGGING
     if (!gGtkIMLog) {
         gGtkIMLog = PR_NewLogModule("nsGtkIMModuleWidgets");
     }
 #endif
+    static bool sFirstInstance = true;
+    if (sFirstInstance) {
+        sFirstInstance = false;
+        sUseSimpleContext =
+            Preferences::GetBool(
+                "intl.ime.use_simple_context_on_password_field",
+                kUseSimpleContextDefault);
+    }
     Init();
 }
 
 void
 nsGtkIMModule::Init()
 {
     PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
         ("GtkIMModule(%p): Init, mOwnerWindow=%p",
@@ -112,36 +123,38 @@ nsGtkIMModule::Init()
     g_signal_connect(mContext, "preedit_start",
                      G_CALLBACK(nsGtkIMModule::OnStartCompositionCallback),
                      this);
     g_signal_connect(mContext, "preedit_end",
                      G_CALLBACK(nsGtkIMModule::OnEndCompositionCallback),
                      this);
 
     // Simple context
-    mSimpleContext = gtk_im_context_simple_new();
-    gtk_im_context_set_client_window(mSimpleContext, gdkWindow);
-    g_signal_connect(mSimpleContext, "preedit_changed",
-                     G_CALLBACK(&nsGtkIMModule::OnChangeCompositionCallback),
-                     this);
-    g_signal_connect(mSimpleContext, "retrieve_surrounding",
-                     G_CALLBACK(&nsGtkIMModule::OnRetrieveSurroundingCallback),
-                     this);
-    g_signal_connect(mSimpleContext, "delete_surrounding",
-                     G_CALLBACK(&nsGtkIMModule::OnDeleteSurroundingCallback),
-                     this);
-    g_signal_connect(mSimpleContext, "commit",
-                     G_CALLBACK(&nsGtkIMModule::OnCommitCompositionCallback),
-                     this);
-    g_signal_connect(mSimpleContext, "preedit_start",
-                     G_CALLBACK(nsGtkIMModule::OnStartCompositionCallback),
-                     this);
-    g_signal_connect(mSimpleContext, "preedit_end",
-                     G_CALLBACK(nsGtkIMModule::OnEndCompositionCallback),
-                     this);
+    if (sUseSimpleContext) {
+        mSimpleContext = gtk_im_context_simple_new();
+        gtk_im_context_set_client_window(mSimpleContext, gdkWindow);
+        g_signal_connect(mSimpleContext, "preedit_changed",
+            G_CALLBACK(&nsGtkIMModule::OnChangeCompositionCallback),
+            this);
+        g_signal_connect(mSimpleContext, "retrieve_surrounding",
+            G_CALLBACK(&nsGtkIMModule::OnRetrieveSurroundingCallback),
+            this);
+        g_signal_connect(mSimpleContext, "delete_surrounding",
+            G_CALLBACK(&nsGtkIMModule::OnDeleteSurroundingCallback),
+            this);
+        g_signal_connect(mSimpleContext, "commit",
+            G_CALLBACK(&nsGtkIMModule::OnCommitCompositionCallback),
+            this);
+        g_signal_connect(mSimpleContext, "preedit_start",
+            G_CALLBACK(nsGtkIMModule::OnStartCompositionCallback),
+            this);
+        g_signal_connect(mSimpleContext, "preedit_end",
+            G_CALLBACK(nsGtkIMModule::OnEndCompositionCallback),
+            this);
+    }
 
     // Dummy context
     mDummyContext = gtk_im_multicontext_new();
     gtk_im_context_set_client_window(mDummyContext, gdkWindow);
 }
 
 nsGtkIMModule::~nsGtkIMModule()
 {
@@ -563,17 +576,35 @@ nsGtkIMModule::SetInputContext(nsWindow*
     if (changingEnabledState) {
 #if (MOZ_WIDGET_GTK == 3)
         static bool sInputPurposeSupported = !gtk_check_version(3, 6, 0);
         if (sInputPurposeSupported && IsEditable()) {
             GtkIMContext* context = GetContext();
             if (context) {
                 GtkInputPurpose purpose = GTK_INPUT_PURPOSE_FREE_FORM;
                 const nsString& inputType = mInputContext.mHTMLInputType;
-                if (inputType.EqualsLiteral("password")) {
+                // Password case has difficult issue.  Desktop IMEs disable
+                // composition if input-purpose is password.
+                // For disabling IME on |ime-mode: disabled;|, we need to check
+                // mEnabled value instead of inputType value.  This hack also
+                // enables composition on
+                // <input type="password" style="ime-mode: enabled;">.
+                // This is right behavior of ime-mode on desktop.
+                //
+                // On the other hand, IME for tablet devices may provide a
+                // specific software keyboard for password field.  If so,
+                // the behavior might look strange on both:
+                //   <input type="text" style="ime-mode: disabled;">
+                //   <input type="password" style="ime-mode: enabled;">
+                //
+                // Temporarily, we should focus on desktop environment for now.
+                // I.e., let's ignore tablet devices for now.  When somebody
+                // reports actual trouble on tablet devices, we should try to
+                // look for a way to solve actual problem.
+                if (mInputContext.mIMEState.mEnabled == IMEState::PASSWORD) {
                     purpose = GTK_INPUT_PURPOSE_PASSWORD;
                 } else if (inputType.EqualsLiteral("email")) {
                     purpose = GTK_INPUT_PURPOSE_EMAIL;
                 } else if (inputType.EqualsLiteral("url")) {
                     purpose = GTK_INPUT_PURPOSE_URL;
                 } else if (inputType.EqualsLiteral("tel")) {
                     purpose = GTK_INPUT_PURPOSE_PHONE;
                 } else if (inputType.EqualsLiteral("number")) {
@@ -621,17 +652,19 @@ nsGtkIMModule::GetContext()
     }
     return mDummyContext;
 }
 
 bool
 nsGtkIMModule::IsEnabled()
 {
     return mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
-           mInputContext.mIMEState.mEnabled == IMEState::PLUGIN;
+           mInputContext.mIMEState.mEnabled == IMEState::PLUGIN ||
+           (!sUseSimpleContext &&
+            mInputContext.mIMEState.mEnabled == IMEState::PASSWORD);
 }
 
 bool
 nsGtkIMModule::IsEditable()
 {
     return mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
            mInputContext.mIMEState.mEnabled == IMEState::PLUGIN ||
            mInputContext.mIMEState.mEnabled == IMEState::PASSWORD;
--- a/widget/gtk/nsGtkIMModule.h
+++ b/widget/gtk/nsGtkIMModule.h
@@ -101,19 +101,19 @@ protected:
 
     // A last focused window in this class's context.
     nsWindow* mLastFocusedWindow;
 
     // Actual context. This is used for handling the user's input.
     GtkIMContext       *mContext;
 
     // mSimpleContext is used for the password field and
-    // the |ime-mode: disabled;| editors.  These editors disable IME.
-    // But dead keys should work.  Fortunately, the simple IM context of
-    // GTK2 support only them.
+    // the |ime-mode: disabled;| editors if sUseSimpleContext is true.
+    // These editors disable IME.  But dead keys should work.  Fortunately,
+    // the simple IM context of GTK2 support only them.
     GtkIMContext       *mSimpleContext;
 
     // mDummyContext is a dummy context and will be used in Focus()
     // when the state of mEnabled means disabled.  This context's IME state is
     // always "closed", so it closes IME forcedly.
     GtkIMContext       *mDummyContext;
 
     // IME enabled state and other things defined in InputContext.
@@ -198,16 +198,21 @@ protected:
     // Then, DispatchCompositionStart() doesn't dispatch keydown event.
     bool mKeyDownEventWasSent;
 
     // sLastFocusedModule is a pointer to the last focused instance of this
     // class.  When a instance is destroyed and sLastFocusedModule refers it,
     // this is cleared.  So, this refers valid pointer always.
     static nsGtkIMModule* sLastFocusedModule;
 
+    // sUseSimpleContext indeicates if password editors and editors with
+    // |ime-mode: disabled;| should use GtkIMContextSimple.
+    // If true, they use GtkIMContextSimple.  Otherwise, not.
+    static bool sUseSimpleContext;
+
     // Callback methods for native IME events.  These methods should call
     // the related instance methods simply.
     static gboolean OnRetrieveSurroundingCallback(GtkIMContext  *aContext,
                                                   nsGtkIMModule *aModule);
     static gboolean OnDeleteSurroundingCallback(GtkIMContext  *aContext,
                                                 gint           aOffset,
                                                 gint           aNChars,
                                                 nsGtkIMModule *aModule);