Bug 1384829 - 1. Always perform shadow text actions; r?esawin draft
authorJim Chen <nchen@mozilla.com>
Thu, 28 Sep 2017 00:14:18 -0400
changeset 671598 c61b0faffff48fe6a2b5f26bc05b6b200e8dc440
parent 671250 6100472d3aa833dff22a4edb0934fe600f43ddb8
child 671599 6df4f06ff4cab571707e4f6baaf5ffeaa856a941
push id81991
push userbmo:nchen@mozilla.com
push dateThu, 28 Sep 2017 04:15:12 +0000
reviewersesawin
bugs1384829
milestone58.0a1
Bug 1384829 - 1. Always perform shadow text actions; r?esawin We want to always perform actions on the shadow text side even if a particular GeckoEditable instance is disconnected from Gecko, because there could be other users of Editable that still expect the object to perform valid actions. MozReview-Commit-ID: 48OIEaPZqUE
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -446,18 +446,43 @@ final class GeckoEditable extends IGecko
 
     private void icOfferAction(final Action action) {
         if (DEBUG) {
             assertOnIcThread();
             Log.d(LOGTAG, "offer: Action(" +
                           getConstantName(Action.class, "TYPE_", action.mType) + ")");
         }
 
+        switch (action.mType) {
+            case Action.TYPE_EVENT:
+            case Action.TYPE_SET_HANDLER:
+                break;
+
+            case Action.TYPE_SET_SPAN:
+                mText.shadowSetSpan(action.mSpanObject, action.mStart,
+                                    action.mEnd, action.mSpanFlags);
+                break;
+
+            case Action.TYPE_REMOVE_SPAN:
+                action.mSpanFlags = mText.getShadowText().getSpanFlags(action.mSpanObject);
+                mText.shadowRemoveSpan(action.mSpanObject);
+                break;
+
+            case Action.TYPE_REPLACE_TEXT:
+                mText.shadowReplace(action.mStart, action.mEnd, action.mSequence);
+                break;
+
+            default:
+                throw new IllegalStateException("Action not processed");
+        }
+
+        // Always perform actions on the shadow text side above, so we still act as a
+        // valid Editable object, but don't send the actions to Gecko below if we haven't
+        // been focused or initialized, or we've been destroyed.
         if (mFocusedChild == null || mListener == null) {
-            // We haven't been focused or initialized, or we've been destroyed.
             return;
         }
 
         mActions.offer(action);
 
         try {
             icPerformAction(action);
         } catch (final RemoteException e) {
@@ -475,35 +500,31 @@ final class GeckoEditable extends IGecko
             break;
 
         case Action.TYPE_SET_SPAN: {
             final boolean needUpdate = (action.mSpanFlags & Spanned.SPAN_INTERMEDIATE) == 0 &&
                                        ((action.mSpanFlags & Spanned.SPAN_COMPOSING) != 0 ||
                                         action.mSpanObject == Selection.SELECTION_START ||
                                         action.mSpanObject == Selection.SELECTION_END);
 
-            mText.shadowSetSpan(action.mSpanObject, action.mStart,
-                                action.mEnd, action.mSpanFlags);
             action.mSequence = TextUtils.substring(
                     mText.getShadowText(), action.mStart, action.mEnd);
 
             mNeedUpdateComposition |= needUpdate;
             if (needUpdate) {
                 icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO |
                                                               SEND_COMPOSITION_KEEP_CURRENT);
             }
 
             mFocusedChild.onImeSynchronize();
             break;
         }
         case Action.TYPE_REMOVE_SPAN: {
-            final int flags = mText.getShadowText().getSpanFlags(action.mSpanObject);
-            final boolean needUpdate = (flags & Spanned.SPAN_INTERMEDIATE) == 0 &&
-                                       (flags & Spanned.SPAN_COMPOSING) != 0;
-            mText.shadowRemoveSpan(action.mSpanObject);
+            final boolean needUpdate = (action.mSpanFlags & Spanned.SPAN_INTERMEDIATE) == 0 &&
+                                       (action.mSpanFlags & Spanned.SPAN_COMPOSING) != 0;
 
             mNeedUpdateComposition |= needUpdate;
             if (needUpdate) {
                 icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO |
                                                               SEND_COMPOSITION_KEEP_CURRENT);
             }
 
             mFocusedChild.onImeSynchronize();
@@ -516,17 +537,16 @@ final class GeckoEditable extends IGecko
 
             // Because we get composition styling here essentially for free,
             // we don't need to check if we're in batch mode.
             if (!icMaybeSendComposition(
                     action.mSequence, SEND_COMPOSITION_USE_ENTIRE_TEXT)) {
                 // Since we don't have a composition, we can try sending key events.
                 sendCharKeyEvents(action);
             }
-            mText.shadowReplace(action.mStart, action.mEnd, action.mSequence);
             mFocusedChild.onImeReplaceText(
                     action.mStart, action.mEnd, action.mSequence.toString());
             break;
 
         default:
             throw new IllegalStateException("Action not processed");
         }
     }