diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 52a9b9a6cc89523e62b06a0b7c03e89de4ee239b..57eaa3836ce8798b16d5cb35654a770752c5c119 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -2495,11 +2495,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (null == range) return; // Happens if we don't have an input connection at all
         // If for some strange reason (editor bug or so) we measure the text before the cursor as
         // longer than what the entire text is supposed to be, the safe thing to do is bail out.
-        if (range.mCharsBefore > mLastSelectionStart) return;
+        final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor();
+        if (numberOfCharsInWordBeforeCursor > mLastSelectionStart) return;
         final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
-        final String typedWord = range.mWord.toString();
-        if (range.mWord instanceof SpannableString) {
-            final SpannableString spannableString = (SpannableString)range.mWord;
+        final CharSequence word = range.mWord;
+        final String typedWord = word.toString();
+        if (word instanceof SpannableString) {
+            final SpannableString spannableString = (SpannableString)word;
             int i = 0;
             for (Object object : spannableString.getSpans(0, spannableString.length(),
                     SuggestionSpan.class)) {
@@ -2515,9 +2517,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             }
         }
         mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
-        mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
-        mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
-                mLastSelectionEnd + range.mCharsAfter);
+        mWordComposer.setCursorPositionWithinWord(numberOfCharsInWordBeforeCursor);
+        mConnection.setComposingRegion(
+                mLastSelectionStart - numberOfCharsInWordBeforeCursor,
+                mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor());
         final SuggestedWords suggestedWords;
         if (suggestions.isEmpty()) {
             // We come here if there weren't any suggestion spans on this word. We will try to
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 980215de6f67cdcfed20b022e88d33d18a6180b6..4031e77bc0bd6c21b450394a0131e320bbf82e95 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.latin;
 
 import android.inputmethodservice.InputMethodService;
-import android.text.SpannableString;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -441,25 +440,33 @@ public final class RichInputConnection {
      * Represents a range of text, relative to the current cursor position.
      */
     public static final class Range {
-        /** Characters before selection start */
-        public final int mCharsBefore;
+        private final CharSequence mTextAtCursor;
+        private final int mWordAtCursorStartIndex;
+        private final int mWordAtCursorEndIndex;
+        private final int mCursorIndex;
 
-        /**
-         * Characters after selection start, including one trailing word
-         * separator.
-         */
-        public final int mCharsAfter;
-
-        /** The actual characters that make up a word */
         public final CharSequence mWord;
 
-        public Range(int charsBefore, int charsAfter, CharSequence word) {
-            if (charsBefore < 0 || charsAfter < 0) {
+        public int getNumberOfCharsInWordBeforeCursor() {
+            return mCursorIndex - mWordAtCursorStartIndex;
+        }
+
+        public int getNumberOfCharsInWordAfterCursor() {
+            return mWordAtCursorEndIndex - mCursorIndex;
+        }
+
+        public Range(final CharSequence textAtCursor, final int wordAtCursorStartIndex,
+                final int wordAtCursorEndIndex, final int cursorIndex) {
+            if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex
+                    || cursorIndex > wordAtCursorEndIndex
+                    || wordAtCursorEndIndex > textAtCursor.length()) {
                 throw new IndexOutOfBoundsException();
             }
-            this.mCharsBefore = charsBefore;
-            this.mCharsAfter = charsAfter;
-            this.mWord = word;
+            mTextAtCursor = textAtCursor;
+            mWordAtCursorStartIndex = wordAtCursorStartIndex;
+            mWordAtCursorEndIndex = wordAtCursorEndIndex;
+            mCursorIndex = cursorIndex;
+            mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex);
         }
     }
 
@@ -571,10 +578,8 @@ public final class RichInputConnection {
             }
         }
 
-        final SpannableString word = new SpannableString(TextUtils.concat(
-                before.subSequence(startIndexInBefore, before.length()),
-                after.subSequence(0, endIndexInAfter)));
-        return new Range(before.length() - startIndexInBefore, endIndexInAfter, word);
+        return new Range(TextUtils.concat(before, after), startIndexInBefore,
+                before.length() + endIndexInAfter, before.length());
     }
 
     public boolean isCursorTouchingWord(final SettingsValues settingsValues) {