Bug 810170 - Properly handle extracted text notification and selection notification; r=cpeterson
authorJim Chen <nchen@mozilla.com>
Tue, 13 Nov 2012 17:26:18 -0500
changeset 113146 cbff9c26a1b2c688ede1ff8eeb0405136754e1b1
parent 113145 9707fdeafe857f02c6d70658656f2218bedb84bb
child 113147 c38480ca4ee4932c0eada6bc5567e55a036c8cd8
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
bugs810170
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 810170 - Properly handle extracted text notification and selection notification; r=cpeterson
mobile/android/base/GeckoEditable.java
mobile/android/base/GeckoInputConnection.java
--- a/mobile/android/base/GeckoEditable.java
+++ b/mobile/android/base/GeckoEditable.java
@@ -548,24 +548,24 @@ final class GeckoEditable
                 // Replace using saved text to preserve spans
                 mText.replace(start, oldEnd, action.mSequence,
                               0, action.mSequence.length());
             } else {
                 mText.replace(start, oldEnd, text, 0, text.length());
             }
         } else {
             mText.replace(start, oldEnd, text, 0, text.length());
-            geckoPostToUI(new Runnable() {
-                public void run() {
-                    if (mListener != null) {
-                        mListener.onTextChange(text, start, oldEnd, newEnd);
-                    }
+        }
+        geckoPostToUI(new Runnable() {
+            public void run() {
+                if (mListener != null) {
+                    mListener.onTextChange(text, start, oldEnd, newEnd);
                 }
-            });
-        }
+            }
+        });
     }
 
     // InvocationHandler interface
 
     private static StringBuilder debugAppend(StringBuilder sb, Object obj) {
         if (obj == null) {
             sb.append("null");
         } else if (obj instanceof GeckoEditable) {
@@ -635,19 +635,17 @@ final class GeckoEditable
     @Override
     public void removeSpan(Object what) {
         if (what == Selection.SELECTION_START ||
                 what == Selection.SELECTION_END) {
             Log.w(LOGTAG, "selection removed with removeSpan()");
         }
         // Okay to remove immediately
         mText.removeSpan(what);
-        if (mUpdateGecko) {
-            mActionQueue.offer(new Action(Action.TYPE_REMOVE_SPAN));
-        }
+        mActionQueue.offer(new Action(Action.TYPE_REMOVE_SPAN));
     }
 
     @Override
     public void setSpan(Object what, int start, int end, int flags) {
         if (what == Selection.SELECTION_START) {
             if ((flags & Spanned.SPAN_INTERMEDIATE) != 0) {
                 // We will get the end offset next, just save the start for now
                 mSavedSelectionStart = start;
--- a/mobile/android/base/GeckoInputConnection.java
+++ b/mobile/android/base/GeckoInputConnection.java
@@ -59,16 +59,18 @@ class GeckoInputConnection
     private static String mIMEActionHint = "";
 
     private String mCurrentInputMethod;
 
     private final GeckoEditableClient mEditableClient;
     protected int mBatchEditCount;
     private ExtractedTextRequest mUpdateRequest;
     private final ExtractedText mUpdateExtract = new ExtractedText();
+    private boolean mBatchSelectionChanged;
+    private boolean mBatchTextChanged;
 
     public static InputConnectionHandler create(View targetView,
                                                 GeckoEditableClient editable) {
         if (DEBUG)
             return DebugGeckoInputConnection.create(targetView, editable);
         else
             return new GeckoInputConnection(targetView, editable);
     }
@@ -89,16 +91,26 @@ class GeckoInputConnection
         return true;
     }
 
     @Override
     public synchronized boolean endBatchEdit() {
         if (mBatchEditCount > 0) {
             mBatchEditCount--;
             if (mBatchEditCount == 0) {
+                if (mBatchTextChanged) {
+                    notifyTextChange();
+                    mBatchTextChanged = false;
+                }
+                if (mBatchSelectionChanged) {
+                    Editable editable = getEditable();
+                    notifySelectionChange(Selection.getSelectionStart(editable),
+                                           Selection.getSelectionEnd(editable));
+                    mBatchSelectionChanged = false;
+                }
                 mEditableClient.setUpdateGecko(true);
             }
         } else {
             Log.w(LOGTAG, "endBatchEdit() called, but mBatchEditCount == 0?!");
         }
         return true;
     }
 
@@ -186,48 +198,64 @@ class GeckoInputConnection
             return null;
         }
         Context context = view.getContext();
         return InputMethods.getInputMethodManager(context);
     }
 
     public void onTextChange(String text, int start, int oldEnd, int newEnd) {
 
-        if (mBatchEditCount > 0 || mUpdateRequest == null) {
+        if (mUpdateRequest == null) {
             return;
         }
 
+        if (mBatchEditCount > 0) {
+            // Delay notification until after the batch edit
+            mBatchTextChanged = true;
+            return;
+        }
+        notifyTextChange();
+    }
+
+    private void notifyTextChange() {
+
         final InputMethodManager imm = getInputMethodManager();
         if (imm == null) {
             return;
         }
         final View v = getView();
         final Editable editable = getEditable();
 
         mUpdateExtract.flags = 0;
-        // Update from (0, oldEnd) to (0, newEnd) because some IMEs
-        // assume that updates start at zero, according to jchen.
-        mUpdateExtract.partialStartOffset = 0;
-        mUpdateExtract.partialEndOffset = editable.length();
+        // Update the entire Editable range
+        mUpdateExtract.partialStartOffset = -1;
+        mUpdateExtract.partialEndOffset = -1;
         mUpdateExtract.selectionStart =
                 Selection.getSelectionStart(editable);
         mUpdateExtract.selectionEnd =
                 Selection.getSelectionEnd(editable);
         mUpdateExtract.startOffset = 0;
         mUpdateExtract.text = editable;
 
         imm.updateExtractedText(v, mUpdateRequest.token,
                                 mUpdateExtract);
     }
 
     public void onSelectionChange(int start, int end) {
 
         if (mBatchEditCount > 0) {
+            // Delay notification until after the batch edit
+            mBatchSelectionChanged = true;
             return;
         }
+        notifySelectionChange(start, end);
+    }
+
+    private void notifySelectionChange(int start, int end) {
+
         final InputMethodManager imm = getInputMethodManager();
         if (imm == null) {
             return;
         }
         final View v = getView();
         final Editable editable = getEditable();
         imm.updateSelection(v, start, end, getComposingSpanStart(editable),
                             getComposingSpanEnd(editable));