Bug 808287 - Fix out-of-order IME events during focus change; r=cpeterson
authorJim Chen <nchen@mozilla.com>
Tue, 13 Nov 2012 17:27:19 -0500
changeset 113147 c38480ca4ee4932c0eada6bc5567e55a036c8cd8
parent 113146 cbff9c26a1b2c688ede1ff8eeb0405136754e1b1
child 113148 da23f50dc0a9d571f4934ca387622232ab1eb1de
push id23859
push useremorley@mozilla.com
push dateWed, 14 Nov 2012 14:36:31 +0000
treeherdermozilla-central@87928cd21b40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpeterson
bugs808287
milestone19.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 808287 - Fix out-of-order IME events during focus change; r=cpeterson
mobile/android/base/GeckoEditable.java
mobile/android/base/GeckoEvent.java
widget/android/AndroidJavaWrappers.h
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/mobile/android/base/GeckoEditable.java
+++ b/mobile/android/base/GeckoEditable.java
@@ -48,16 +48,17 @@ interface GeckoEditableListener {
 */
 final class GeckoEditable
         implements InvocationHandler, Editable,
                    GeckoEditableClient, GeckoEditableListener {
 
     private static final boolean DEBUG = false;
     private static final String LOGTAG = "GeckoEditable";
     private static final int NOTIFY_IME_REPLY_EVENT = 1;
+    private static final int NOTIFY_IME_FOCUSCHANGE = 3;
 
     // Filters to implement Editable's filtering functionality
     private InputFilter[] mFilters;
 
     private final SpannableStringBuilder mText;
     private final Editable mProxy;
     private GeckoEditableListener mListener;
     private final ActionQueue mActionQueue;
@@ -459,16 +460,21 @@ final class GeckoEditable
         if (type == NOTIFY_IME_REPLY_EVENT) {
             geckoActionReply();
             return;
         }
         geckoPostToUI(new Runnable() {
             public void run() {
                 // Make sure there are no other things going on
                 mActionQueue.syncWithGecko();
+                if (type == NOTIFY_IME_FOCUSCHANGE && state != 0) {
+                    // Unmask events on the Gecko side
+                    GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent(
+                            GeckoEvent.IME_ACKNOWLEDGE_FOCUS));
+                }
                 if (mListener != null) {
                     mListener.notifyIME(type, state);
                 }
             }
         });
     }
 
     @Override
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -81,16 +81,17 @@ public class GeckoEvent {
     private static final int DOM_KEY_LOCATION_JOYSTICK = 5;
 
     public static final int IME_SYNCHRONIZE = 0;
     public static final int IME_REPLACE_TEXT = 1;
     public static final int IME_SET_SELECTION = 2;
     public static final int IME_ADD_COMPOSITION_RANGE = 3;
     public static final int IME_UPDATE_COMPOSITION = 4;
     public static final int IME_REMOVE_COMPOSITION = 5;
+    public static final int IME_ACKNOWLEDGE_FOCUS = 6;
 
     public static final int IME_RANGE_CARETPOSITION = 1;
     public static final int IME_RANGE_RAWINPUT = 2;
     public static final int IME_RANGE_SELECTEDRAWTEXT = 3;
     public static final int IME_RANGE_CONVERTEDTEXT = 4;
     public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5;
 
     public static final int IME_RANGE_UNDERLINE = 1;
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -810,17 +810,18 @@ public:
     };
 
     enum {
         IME_SYNCHRONIZE = 0,
         IME_REPLACE_TEXT = 1,
         IME_SET_SELECTION = 2,
         IME_ADD_COMPOSITION_RANGE = 3,
         IME_UPDATE_COMPOSITION = 4,
-        IME_REMOVE_COMPOSITION = 5
+        IME_REMOVE_COMPOSITION = 5,
+        IME_ACKNOWLEDGE_FOCUS = 6
     };
 };
 
 class nsJNIString : public nsString
 {
 public:
     nsJNIString(jstring jstr, JNIEnv *jenv);
 };
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -158,17 +158,19 @@ nsWindow::DumpWindows(const nsTArray<nsW
 }
 
 nsWindow::nsWindow() :
     mIsVisible(false),
     mParent(nullptr),
     mFocus(nullptr),
     mIMEComposing(false),
     mIMEMaskSelectionUpdate(false),
-    mIMEMaskTextUpdate(false)
+    mIMEMaskTextUpdate(false),
+    // Mask IME events initially because there is no focused editors yet
+    mIMEMaskEvents(true)
 {
 }
 
 nsWindow::~nsWindow()
 {
     gTopLevelWindows.RemoveElement(this);
     nsWindow *top = FindTopLevel();
     if (top->mFocus == this)
@@ -1875,16 +1877,28 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *
         * Gecko controls the text content, and Java shadows the Gecko text
            through text updates
         * Java controls the selection, and Gecko shadows the Java selection
            through set selection events
         * Java controls the composition, and Gecko shadows the Java
            composition through update composition events
     */
     nsRefPtr<nsWindow> kungFuDeathGrip(this);
+
+    if (ae->Action() == AndroidGeckoEvent::IME_ACKNOWLEDGE_FOCUS) {
+        mIMEMaskEvents = false;
+        return;
+    } else if (mIMEMaskEvents) {
+        // Still reply to events, but don't do anything else
+        if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE ||
+                ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) {
+            AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0);
+        }
+        return;
+    }
     switch (ae->Action()) {
     case AndroidGeckoEvent::IME_SYNCHRONIZE:
         {
             AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0);
         }
         break;
     case AndroidGeckoEvent::IME_REPLACE_TEXT:
         {
@@ -2161,16 +2175,21 @@ nsWindow::CancelIMEComposition()
 NS_IMETHODIMP
 nsWindow::OnIMEFocusChange(bool aFocus)
 {
     ALOGIME("IME: OnIMEFocusChange: f=%d", aFocus);
 
     if (aFocus) {
         OnIMETextChange(0, INT32_MAX, INT32_MAX);
         OnIMESelectionChange();
+    } else {
+        // Mask events because we lost focus. On the next focus event, Gecko will notify
+        // Java, and Java will send an acknowledge focus event back to Gecko. That is
+        // where we unmask event handling
+        mIMEMaskEvents = true;
     }
 
     AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_FOCUSCHANGE,
                              int(aFocus));
 
     return NS_OK;
 }
 
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -179,16 +179,17 @@ protected:
 
     double mStartDist;
     double mLastDist;
 
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
 
     bool mIMEComposing;
     bool mIMEMaskSelectionUpdate, mIMEMaskTextUpdate;
+    bool mIMEMaskEvents;
     nsString mIMEComposingText;
     nsAutoTArray<nsTextRange, 4> mIMERanges;
 
     InputContext mInputContext;
 
     static void DumpWindows();
     static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0);
     static void LogWindow(nsWindow *win, int index, int indent);