Merge "Remove mPrevWordsInfo"

This commit is contained in:
Jean Chalard 2014-06-10 03:21:47 +00:00 committed by Android (Google) Code Review
commit 264afb10bd
5 changed files with 57 additions and 133 deletions

View File

@ -110,7 +110,7 @@ public final class Suggest {
wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions, SESSION_TYPING, rawSuggestions);
final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
final boolean isOnlyFirstCharCapitalized = wordComposer.isOnlyFirstCharCapitalized();
// If resumed, then we don't want to upcase everything: resuming on a fully-capitalized
// words is rarely done to switch to another fully-capitalized word, but usually to a
// normal, non-capitalized suggestion.
@ -122,7 +122,7 @@ public final class Suggest {
} else {
final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo(
suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase,
isFirstCharCapitalized, trailingSingleQuotesCount);
isOnlyFirstCharCapitalized, trailingSingleQuotesCount);
firstSuggestion = firstSuggestedWordInfo.mWord;
if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
whitelistedWord = null;
@ -142,7 +142,7 @@ public final class Suggest {
final boolean allowsToBeAutoCorrected = (null != whitelistedWord
&& !whitelistedWord.equals(typedWord))
|| (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord(
consideredWord, wordComposer.isFirstCharCapitalized())
consideredWord, isOnlyFirstCharCapitalized)
&& !typedWord.equals(firstSuggestion));
final boolean hasAutoCorrection;
@ -173,12 +173,12 @@ public final class Suggest {
final ArrayList<SuggestedWordInfo> suggestionsContainer =
new ArrayList<>(suggestionResults);
final int suggestionsCount = suggestionsContainer.size();
if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) {
if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized,
trailingSingleQuotesCount);
wordInfo, suggestionResults.mLocale, isAllUpperCase,
isOnlyFirstCharCapitalized, trailingSingleQuotesCount);
suggestionsContainer.set(i, transformedWordInfo);
}
}
@ -292,11 +292,11 @@ public final class Suggest {
/* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo(
final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase,
final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) {
final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) {
final StringBuilder sb = new StringBuilder(wordInfo.mWord.length());
if (isAllUpperCase) {
sb.append(wordInfo.mWord.toUpperCase(locale));
} else if (isFirstCharCapitalized) {
} else if (isOnlyFirstCharCapitalized) {
sb.append(StringUtils.capitalizeFirstCodePoint(wordInfo.mWord, locale));
} else {
sb.append(wordInfo.mWord);

View File

@ -45,9 +45,6 @@ public final class WordComposer {
// The list of events that served to compose this string.
private final ArrayList<Event> mEvents;
private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH);
// The information of previous words (before the composing word). Must not be null. Used as
// context for suggestions.
private PrevWordsInfo mPrevWordsInfo;
private String mAutoCorrection;
private boolean mIsResumed;
private boolean mIsBatchMode;
@ -72,9 +69,9 @@ public final class WordComposer {
private int mCursorPositionWithinWord;
/**
* Whether the user chose to capitalize the first char of the word.
* Whether the composing word has the only first char capitalized.
*/
private boolean mIsFirstCharCapitalized;
private boolean mIsOnlyFirstCharCapitalized;
public WordComposer() {
mCombinerChain = new CombinerChain("");
@ -84,7 +81,6 @@ public final class WordComposer {
mIsBatchMode = false;
mCursorPositionWithinWord = 0;
mRejectedBatchModeSuggestion = null;
mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
refreshTypedWordCache();
}
@ -111,12 +107,11 @@ public final class WordComposer {
mAutoCorrection = null;
mCapsCount = 0;
mDigitsCount = 0;
mIsFirstCharCapitalized = false;
mIsOnlyFirstCharCapitalized = false;
mIsResumed = false;
mIsBatchMode = false;
mCursorPositionWithinWord = 0;
mRejectedBatchModeSuggestion = null;
mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
refreshTypedWordCache();
}
@ -178,12 +173,6 @@ public final class WordComposer {
return mInputPointers;
}
private static boolean isFirstCharCapitalized(final int index, final int codePoint,
final boolean previous) {
if (index == 0) return Character.isUpperCase(codePoint);
return previous && !Character.isUpperCase(codePoint);
}
/**
* Process an input event.
*
@ -203,7 +192,7 @@ public final class WordComposer {
mCursorPositionWithinWord = mCodePointSize;
// We may have deleted the last one.
if (0 == mCodePointSize) {
mIsFirstCharCapitalized = false;
mIsOnlyFirstCharCapitalized = false;
}
if (Constants.CODE_DELETE != event.mKeyCode) {
if (newIndex < MAX_WORD_LENGTH) {
@ -215,8 +204,12 @@ public final class WordComposer {
mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0);
}
}
mIsFirstCharCapitalized = isFirstCharCapitalized(
newIndex, primaryCode, mIsFirstCharCapitalized);
if (0 == newIndex) {
mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode);
} else {
mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized
&& !Character.isUpperCase(primaryCode);
}
if (Character.isUpperCase(primaryCode)) mCapsCount++;
if (Character.isDigit(primaryCode)) mDigitsCount++;
}
@ -296,10 +289,8 @@ public final class WordComposer {
* This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
* @param codePoints the code points to set as the composing word.
* @param coordinates the x, y coordinates of the key in the CoordinateUtils format
* @param prevWordsInfo the information of previous words, to use as context for suggestions
*/
public void setComposingWord(final int[] codePoints, final int[] coordinates,
final PrevWordsInfo prevWordsInfo) {
public void setComposingWord(final int[] codePoints, final int[] coordinates) {
reset();
final int length = codePoints.length;
for (int i = 0; i < length; ++i) {
@ -308,7 +299,6 @@ public final class WordComposer {
CoordinateUtils.yFromArray(coordinates, i)));
}
mIsResumed = true;
mPrevWordsInfo = prevWordsInfo;
}
/**
@ -319,16 +309,13 @@ public final class WordComposer {
return mTypedWordCache.toString();
}
public PrevWordsInfo getPrevWordsInfoForSuggestion() {
return mPrevWordsInfo;
}
/**
* Whether or not the user typed a capital letter as the first letter in the word
* Whether or not the user typed a capital letter as the first letter in the word, and no
* other letter is capitalized
* @return capitalization preference
*/
public boolean isFirstCharCapitalized() {
return mIsFirstCharCapitalized;
public boolean isOnlyFirstCharCapitalized() {
return mIsOnlyFirstCharCapitalized;
}
/**
@ -364,7 +351,7 @@ public final class WordComposer {
}
/**
* Saves the caps mode and the previous word at the start of composing.
* Saves the caps mode at the start of composing.
*
* WordComposer needs to know about the caps mode for several reasons. The first is, we need
* to know after the fact what the reason was, to register the correct form into the user
@ -373,12 +360,9 @@ public final class WordComposer {
* Also, batch input needs to know about the current caps mode to display correctly
* capitalized suggestions.
* @param mode the mode at the time of start
* @param prevWordsInfo the information of previous words
*/
public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode,
final PrevWordsInfo prevWordsInfo) {
public void setCapitalizedModeAtStartComposingTime(final int mode) {
mCapitalizedMode = mode;
mPrevWordsInfo = prevWordsInfo;
}
/**
@ -429,11 +413,10 @@ public final class WordComposer {
mCapsCount = 0;
mDigitsCount = 0;
mIsBatchMode = false;
mPrevWordsInfo = new PrevWordsInfo(committedWord.toString());
mCombinerChain.reset();
mEvents.clear();
mCodePointSize = 0;
mIsFirstCharCapitalized = false;
mIsOnlyFirstCharCapitalized = false;
mCapitalizedMode = CAPS_MODE_OFF;
refreshTypedWordCache();
mAutoCorrection = null;
@ -443,15 +426,7 @@ public final class WordComposer {
return lastComposedWord;
}
// Call this when the recorded previous word should be discarded. This is typically called
// when the user inputs a separator that's not whitespace (including the case of the
// double-space-to-period feature).
public void discardPreviousWordForSuggestion() {
mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
}
public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord,
final PrevWordsInfo prevWordsInfo) {
public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) {
mEvents.clear();
Collections.copy(mEvents, lastComposedWord.mEvents);
mInputPointers.set(lastComposedWord.mInputPointers);
@ -462,7 +437,6 @@ public final class WordComposer {
mCursorPositionWithinWord = mCodePointSize;
mRejectedBatchModeSuggestion = null;
mIsResumed = true;
mPrevWordsInfo = prevWordsInfo;
}
public boolean isBatchMode() {

View File

@ -544,11 +544,8 @@ public final class InputLogic {
}
}
mConnection.endBatchEdit();
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()),
// Prev word is 1st word before cursor
getPrevWordsInfoFromNthPreviousWordForSuggestion(
settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */));
mWordComposer.setCapitalizedModeAtStartComposingTime(
getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()));
}
/* The sequence number member is only used in onUpdateBatchInput. It is increased each time
@ -584,10 +581,8 @@ public final class InputLogic {
mSpaceState = SpaceState.PHANTOM;
keyboardSwitcher.requestUpdatingShiftState(
getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState());
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
getActualCapsMode(settingsValues,
keyboardSwitcher.getKeyboardShiftMode()),
new PrevWordsInfo(commitParts[0]));
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode(
settingsValues, keyboardSwitcher.getKeyboardShiftMode()));
++mAutoCommitSequenceNumber;
}
}
@ -724,15 +719,7 @@ public final class InputLogic {
mWordComposer.processEvent(inputTransaction.mEvent);
// If it's the first letter, make note of auto-caps state
if (mWordComposer.isSingleLetter()) {
// We pass 2 to getPreviousWordForSuggestion when the previous code point is a word
// connector. Otherwise, we pass 1 because we were not composing a word yet, so the
// word we want is the 1st word before the cursor.
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
inputTransaction.mShiftState,
getPrevWordsInfoFromNthPreviousWordForSuggestion(
settingsValues.mSpacingAndPunctuations,
settingsValues.mSpacingAndPunctuations.isWordConnector(
mConnection.getCodePointBeforeCursor()) ? 2 : 1));
mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState);
}
mConnection.setComposingText(getTextWithUnderline(
mWordComposer.getTypedWord()), 1);
@ -924,10 +911,8 @@ public final class InputLogic {
// No need to reset mSpaceState, it has already be done (that's why we
// receive it as a parameter)
inputTransaction.setRequiresUpdateSuggestions();
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
WordComposer.CAPS_MODE_OFF,
getPrevWordsInfoFromNthPreviousWordForSuggestion(
inputTransaction.mSettingsValues.mSpacingAndPunctuations, 1));
mWordComposer.setCapitalizedModeAtStartComposingTime(
WordComposer.CAPS_MODE_OFF);
return;
}
} else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) {
@ -1107,7 +1092,6 @@ public final class InputLogic {
final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
.mSentenceSeparatorAndSpace;
mConnection.commitText(textToInsert, 1);
mWordComposer.discardPreviousWordForSuggestion();
return true;
}
return false;
@ -1267,10 +1251,7 @@ public final class InputLogic {
final int expectedCursorPosition = mConnection.getExpectedSelectionStart();
if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) {
// Show predictions.
mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
WordComposer.CAPS_MODE_OFF,
getPrevWordsInfoFromNthPreviousWordForSuggestion(
settingsValues.mSpacingAndPunctuations, 1));
mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF);
mLatinIME.mHandler.postUpdateSuggestionStrip();
return;
}
@ -1322,7 +1303,7 @@ public final class InputLogic {
settingsValues.mSpacingAndPunctuations,
0 == numberOfCharsInWordBeforeCursor ? 1 : 2);
mWordComposer.setComposingWord(codePoints,
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo);
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
mWordComposer.setCursorPositionWithinWord(
typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
@ -1450,7 +1431,7 @@ public final class InputLogic {
// with the typed word, so we need to resume suggestions right away.
final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
mWordComposer.setComposingWord(codePoints,
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo);
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
mConnection.setComposingText(textToCommit, 1);
}
// Don't restart suggestion yet. We'll restart if the user deletes the separator.
@ -1897,21 +1878,6 @@ public final class InputLogic {
// strings.
mLastComposedWord = mWordComposer.commitWord(commitType,
chosenWordWithSuggestions, separatorString, prevWordsInfo);
final boolean shouldDiscardPreviousWordForSuggestion;
if (0 == StringUtils.codePointCount(separatorString)) {
// Separator is 0-length, we can keep the previous word for suggestion. Either this
// was a manual pick or the language has no spaces in which case we want to keep the
// previous word, or it was the keyboard closing or the cursor moving in which case it
// will be reset anyway.
shouldDiscardPreviousWordForSuggestion = false;
} else {
// Otherwise, we discard if the separator contains any non-whitespace.
shouldDiscardPreviousWordForSuggestion =
!StringUtils.containsOnlyWhitespace(separatorString);
}
if (shouldDiscardPreviousWordForSuggestion) {
mWordComposer.discardPreviousWordForSuggestion();
}
}
/**

View File

@ -323,7 +323,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
} else {
coordinates = dictInfo.mKeyboard.getCoordinates(codePoints);
}
composer.setComposingWord(codePoints, coordinates, null /* previousWord */);
composer.setComposingWord(codePoints, coordinates);
// TODO: make a spell checker option to block offensive words or not
final ArrayList<SuggestedWordInfo> suggestions =
dictInfo.mDictionary.getSuggestions(composer, prevWordsInfo,

View File

@ -40,8 +40,7 @@ public class WordComposerTests extends AndroidTestCase {
final int[] COORDINATES_WITHIN_BMP =
CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
final PrevWordsInfo PREV_WORDS_INFO = new PrevWordsInfo("prevword");
wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREV_WORDS_INFO);
wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP);
assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length()));
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
wc.setCursorPositionWithinWord(2);
@ -56,15 +55,12 @@ public class WordComposerTests extends AndroidTestCase {
// Move the cursor to after the 'f'
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
// Check the previous word is still there
assertEquals(PREV_WORDS_INFO, wc.getPrevWordsInfoForSuggestion());
// Move the cursor past the end of the word
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1));
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15));
// Do what LatinIME does when the cursor is moved outside of the word,
// and check the behavior is correct.
wc.reset();
assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
// \uD861\uDED7 is 𨛗, a character outside the BMP
final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh";
@ -73,8 +69,8 @@ public class WordComposerTests extends AndroidTestCase {
final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR =
CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length);
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
wc.setCursorPositionWithinWord(3);
@ -83,55 +79,43 @@ public class WordComposerTests extends AndroidTestCase {
assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
final PrevWordsInfo PREV_WORDS_INFO_STR_WITHIN_BMP = new PrevWordsInfo(STR_WITHIN_BMP);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_STR_WITHIN_BMP);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
wc.setCursorPositionWithinWord(3);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion());
final PrevWordsInfo PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR =
new PrevWordsInfo(STR_WITH_SUPPLEMENTARY_CHAR);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
wc.setCursorPositionWithinWord(3);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR,
wc.getPrevWordsInfoForSuggestion());
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_STR_WITHIN_BMP);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
wc.setCursorPositionWithinWord(3);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3));
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1));
assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion());
final PrevWordsInfo PREV_WORDS_INFO_NULL = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_NULL);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
wc.setCursorPositionWithinWord(3);
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9));
assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10));
assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR,
wc.getPrevWordsInfoForSuggestion());
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_NULL);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11));
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_NULL);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
PREV_WORDS_INFO_NULL);
wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
COORDINATES_WITH_SUPPLEMENTARY_CHAR);
wc.setCursorPositionWithinWord(2);
assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
}