diff options
-rw-r--r-- | java/proguard.flags | 4 | ||||
-rw-r--r-- | java/res/values-fr/strings.xml | 4 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/Keyboard.java | 4 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/ProximityInfo.java | 26 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/AutoCorrection.java | 19 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/ExpandableDictionary.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 1 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/Suggest.java | 111 | ||||
-rw-r--r-- | native/src/defines.h | 7 | ||||
-rw-r--r-- | native/src/proximity_info.cpp | 42 | ||||
-rw-r--r-- | native/src/proximity_info.h | 15 | ||||
-rw-r--r-- | native/src/unigram_dictionary.cpp | 124 | ||||
-rw-r--r-- | native/src/unigram_dictionary.h | 7 | ||||
-rw-r--r-- | tests/src/com/android/inputmethod/latin/SuggestHelper.java | 1 |
14 files changed, 227 insertions, 140 deletions
diff --git a/java/proguard.flags b/java/proguard.flags index 9096855e8..729f4ad61 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -14,3 +14,7 @@ void waitUntilUpdateDBDone(); void waitForDictionaryLoading(); } + +-keep class com.android.inputmethod.latin.AutoCorrection { + java.lang.CharSequence getAutoCorrectionWord(); +} diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index c9c6a4530..1c6be41ac 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -40,7 +40,7 @@ <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatique"</string> <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Toujours afficher"</string> <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Toujours masquer"</string> - <string name="auto_correction" msgid="4979925752001319458">"Correction auto."</string> + <string name="auto_correction" msgid="4979925752001319458">"Correction auto"</string> <string name="auto_correction_summary" msgid="5625751551134658006">"Correction auto mots avec barre espace/signes ponctuation"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Désactiver"</string> <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Simple"</string> @@ -84,7 +84,7 @@ <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La saisie vocale fait appel à la reconnaissance vocale de Google. Les "<a href="http://m.google.com/privacy">"Règles de confidentialité Google Mobile"</a>" s\'appliquent."</string> <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pour désactiver la saisie vocale, accédez aux paramètres du mode de saisie."</string> - <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pour utiliser la saisie vocale, appuyez sur le bouton représentant un micro."</string> + <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone."</string> <string name="voice_listening" msgid="467518160751321844">"Parlez maintenant"</string> <string name="voice_working" msgid="6666937792815731889">"Traitement en cours"</string> <string name="voice_initializing" msgid="661962047129906646"></string> diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 3005920b1..06d44680d 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -174,7 +174,7 @@ public class Keyboard { mDefaultHeight = mDefaultWidth; mId = id; loadKeyboard(context, xmlLayoutResId); - mProximityInfo = new ProximityInfo(mDisplayWidth, mDisplayHeight, GRID_WIDTH, GRID_HEIGHT); + mProximityInfo = new ProximityInfo(GRID_WIDTH, GRID_HEIGHT); } public int getProximityInfo() { @@ -378,7 +378,7 @@ public class Keyboard { mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; } } - mProximityInfo.setProximityInfo(mGridNeighbors); + mProximityInfo.setProximityInfo(mGridNeighbors, getMinWidth(), getHeight(), mKeys); } public boolean isInside(Key key, int x, int y) { diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index fcada3762..80d6de952 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -18,18 +18,17 @@ package com.android.inputmethod.keyboard; import com.android.inputmethod.latin.Utils; +import java.util.Arrays; +import java.util.List; + public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; - private final int mDisplayWidth; - private final int mDisplayHeight; private final int mGridWidth; private final int mGridHeight; private final int mGridSize; - ProximityInfo(int displayWidth, int displayHeight, int gridWidth, int gridHeight) { - mDisplayWidth = displayWidth; - mDisplayHeight = displayHeight; + ProximityInfo(int gridWidth, int gridHeight) { mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; @@ -43,20 +42,19 @@ public class ProximityInfo { int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray); private native void releaseProximityInfoNative(int nativeProximityInfo); - public final void setProximityInfo(int[][] gridNeighbors) { + public final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, + int keyboardHeight, List<Key> keys) { int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; + Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); for (int i = 0; i < mGridSize; ++i) { - final int proximityCharsLength = gridNeighbors[i].length; - for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; ++j) { - int charCode = KeyDetector.NOT_A_KEY; - if (j < proximityCharsLength) { - charCode = gridNeighbors[i][j]; - } - proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] = charCode; + final int proximityCharsLength = gridNeighborKeyIndexes[i].length; + for (int j = 0; j < proximityCharsLength; ++j) { + proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] = + keys.get(gridNeighborKeyIndexes[i][j]).mCode; } } mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, - mDisplayWidth, mDisplayHeight, mGridWidth, mGridHeight, proximityCharsArray); + keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray); } // TODO: Get rid of this function's input (keyboard). diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index d1154d9ed..f177f6a71 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin; import android.util.Log; import java.util.ArrayList; +import java.util.Collection; public class AutoCorrection { private static final boolean DBG = LatinImeLogger.sDBG; @@ -45,12 +46,12 @@ public class AutoCorrection { return mNormalizedScore; } - public void updateAutoCorrectionStatus(Suggest suggest, + public void updateAutoCorrectionStatus(Collection<Dictionary> dictionaries, WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] priorities, CharSequence typedWord, double autoCorrectionThreshold, int correctionMode, CharSequence quickFixedWord) { if (hasAutoCorrectionForTypedWord( - suggest, wordComposer, suggestions, typedWord, correctionMode)) { + dictionaries, wordComposer, suggestions, typedWord, correctionMode)) { mHasAutoCorrection = true; mAutoCorrectionWord = typedWord; } else if (hasAutoCorrectForBinaryDictionary(wordComposer, suggestions, correctionMode, @@ -63,9 +64,17 @@ public class AutoCorrection { } } - private boolean hasAutoCorrectionForTypedWord(Suggest suggest, WordComposer wordComposer, - ArrayList<CharSequence> suggestions, CharSequence typedWord, int correctionMode) { - return wordComposer.size() > 1 && suggestions.size() > 0 && suggest.isValidWord(typedWord) + private boolean hasAutoCorrectionForTypedWord(Collection<Dictionary> dictionaries, + WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord, + int correctionMode) { + boolean isValidWord = false; + for (final Dictionary dictionary : dictionaries) { + if (dictionary.isValidWord(typedWord)) { + isValidWord = true; + break; + } + } + return wordComposer.size() > 1 && suggestions.size() > 0 && isValidWord && (correctionMode == Suggest.CORRECTION_FULL || correctionMode == Suggest.CORRECTION_FULL_BIGRAM); } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index f2305f18c..0318175f6 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -225,7 +225,7 @@ public class ExpandableDictionary extends Dictionary { /** * Returns the word's frequency or -1 if not found */ - public int getWordFrequency(CharSequence word) { + protected int getWordFrequency(CharSequence word) { Node node = searchNode(mRoots, word, 0, word.length()); return (node == null) ? -1 : node.mFrequency; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 646de66c2..c66cb5f26 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1427,7 +1427,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void saveWordInHistory(CharSequence result) { if (mWord.size() <= 1) { - mWord.reset(); return; } // Skip if result is null. It happens in some edge case. diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 95a2d631b..ec86a39bb 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -25,6 +25,10 @@ import android.view.View; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** * This class loads a dictionary and provides a list of suggestions for a given sequence of @@ -70,14 +74,13 @@ public class Suggest implements Dictionary.WordCallback { private AutoCorrection mAutoCorrection; private BinaryDictionary mMainDict; - - private Dictionary mUserDictionary; - - private Dictionary mAutoDictionary; - - private Dictionary mContactsDictionary; - - private Dictionary mUserBigramDictionary; + private static final String DICT_KEY_MAIN = "main"; + private static final String DICT_KEY_CONTACTS = "contacts"; + private static final String DICT_KEY_AUTO = "auto"; + private static final String DICT_KEY_USER = "user"; + private static final String DICT_KEY_USER_BIGRAM = "user_bigram"; + private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>(); + private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>(); private int mPrefMaxSuggestions = 12; @@ -101,16 +104,19 @@ public class Suggest implements Dictionary.WordCallback { private int mCorrectionMode = CORRECTION_BASIC; public Suggest(Context context, int dictionaryResId) { - mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN); - init(); + init(BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN)); } /* package for test */ Suggest(File dictionary, long startOffset, long length) { - mMainDict = BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN); - init(); + init(BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN)); } - private void init() { + private void init(BinaryDictionary mainDict) { + if (mainDict != null) { + mMainDict = mainDict; + mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict); + mBigramDictionaries.put(DICT_KEY_MAIN, mainDict); + } mAutoCorrection = new AutoCorrection(); initPool(); } @@ -147,22 +153,28 @@ public class Suggest implements Dictionary.WordCallback { * before the main dictionary, if set. */ public void setUserDictionary(Dictionary userDictionary) { - mUserDictionary = userDictionary; + if (userDictionary != null) + mUnigramDictionaries.put(DICT_KEY_USER, userDictionary); } /** * Sets an optional contacts dictionary resource to be loaded. */ - public void setContactsDictionary(Dictionary userDictionary) { - mContactsDictionary = userDictionary; + public void setContactsDictionary(Dictionary contactsDictionary) { + if (contactsDictionary != null) { + mUnigramDictionaries.put(DICT_KEY_CONTACTS, contactsDictionary); + mBigramDictionaries.put(DICT_KEY_CONTACTS, contactsDictionary); + } } public void setAutoDictionary(Dictionary autoDictionary) { - mAutoDictionary = autoDictionary; + if (autoDictionary != null) + mUnigramDictionaries.put(DICT_KEY_AUTO, autoDictionary); } public void setUserBigramDictionary(Dictionary userBigramDictionary) { - mUserBigramDictionary = userBigramDictionary; + if (userBigramDictionary != null) + mBigramDictionaries.put(DICT_KEY_USER_BIGRAM, userBigramDictionary); } public void setAutoCorrectionThreshold(double threshold) { @@ -240,14 +252,8 @@ public class Suggest implements Dictionary.WordCallback { if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { prevWordForBigram = lowerPrevWord; } - if (mUserBigramDictionary != null) { - mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this); - } - if (mContactsDictionary != null) { - mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this); - } - if (mMainDict != null) { - mMainDict.getBigrams(wordComposer, prevWordForBigram, this); + for (final Dictionary dictionary : mBigramDictionaries.values()) { + dictionary.getBigrams(wordComposer, prevWordForBigram, this); } char currentChar = wordComposer.getTypedWord().charAt(0); char currentCharUpper = Character.toUpperCase(currentChar); @@ -270,15 +276,13 @@ public class Suggest implements Dictionary.WordCallback { } else if (wordComposer.size() > 1) { // At second character typed, search the unigrams (scores being affected by bigrams) - if (mUserDictionary != null || mContactsDictionary != null) { - if (mUserDictionary != null) { - mUserDictionary.getWords(wordComposer, this); - } - if (mContactsDictionary != null) { - mContactsDictionary.getWords(wordComposer, this); - } + for (final String key : mUnigramDictionaries.keySet()) { + // Skip AutoDictionary to lookup + if (key.equals(DICT_KEY_AUTO)) + continue; + final Dictionary dictionary = mUnigramDictionaries.get(key); + dictionary.getWords(wordComposer, this); } - if (mMainDict != null) mMainDict.getWords(wordComposer, this); } CharSequence autoText = null; final String typedWordString = typedWord == null ? null : typedWord.toString(); @@ -324,8 +328,9 @@ public class Suggest implements Dictionary.WordCallback { } } - mAutoCorrection.updateAutoCorrectionStatus(this, wordComposer, mSuggestions, mPriorities, - typedWord, mAutoCorrectionThreshold, mCorrectionMode, autoText); + mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries.values(), wordComposer, + mSuggestions, mPriorities, typedWord, mAutoCorrectionThreshold, mCorrectionMode, + autoText); if (autoText != null) { mSuggestions.add(0, autoText); @@ -515,10 +520,11 @@ public class Suggest implements Dictionary.WordCallback { if (word == null || word.length() == 0 || mMainDict == null) { return false; } - return mMainDict.isValidWord(word) - || (mUserDictionary != null && mUserDictionary.isValidWord(word)) - || (mAutoDictionary != null && mAutoDictionary.isValidWord(word)) - || (mContactsDictionary != null && mContactsDictionary.isValidWord(word)); + for (final Dictionary dictionary : mUnigramDictionaries.values()) { + if (dictionary.isValidWord(word)) + return true; + } + return false; } private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) { @@ -539,25 +545,12 @@ public class Suggest implements Dictionary.WordCallback { } public void close() { - if (mMainDict != null) { - mMainDict.close(); - mMainDict = null; - } - if (mUserDictionary != null) { - mUserDictionary.close(); - mUserDictionary = null; - } - if (mUserBigramDictionary != null) { - mUserBigramDictionary.close(); - mUserBigramDictionary = null; - } - if (mContactsDictionary != null) { - mContactsDictionary.close(); - mContactsDictionary = null; - } - if (mAutoDictionary != null) { - mAutoDictionary.close(); - mAutoDictionary = null; + final Set<Dictionary> dictionaries = new HashSet<Dictionary>(); + dictionaries.addAll(mUnigramDictionaries.values()); + dictionaries.addAll(mBigramDictionaries.values()); + for (final Dictionary dictionary : dictionaries) { + dictionary.close(); } + mMainDict = null; } } diff --git a/native/src/defines.h b/native/src/defines.h index 0d1f037e1..16927e5bb 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -129,10 +129,13 @@ static void prof_out(void) { #define DICTIONARY_HEADER_SIZE 2 #define NOT_VALID_WORD -99 +#define KEYCODE_SPACE ' ' + #define SUGGEST_WORDS_WITH_MISSING_CHARACTER true #define SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER true #define SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER true #define SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS true +#define SUGGEST_WORDS_WITH_SPACE_PROXIMITY true // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent. #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 100 @@ -148,6 +151,10 @@ static void prof_out(void) { #define MAX_DEPTH_MULTIPLIER 3 +// TODO: Reduce this constant if possible; check the maximum number of umlauts in the same German +// word in the dictionary +#define DEFAULT_MAX_UMLAUT_SEARCH_DEPTH 5 + // Minimum suggest depth for one word for all cases except for missing space suggestions. #define MIN_SUGGEST_DEPTH 1 #define MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION 3 diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index d0cba3eb6..5f2d09f5c 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -17,18 +17,48 @@ #include <stdio.h> #include <string.h> +#define LOG_TAG "LatinIME: proximity_info.cpp" + #include "proximity_info.h" namespace latinime { -ProximityInfo::ProximityInfo(int maxProximityCharsSize, int displayWidth, int displayHeight, - int gridWidth, int gridHeight, uint32_t const *proximityCharsArray) - : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), DISPLAY_WIDTH(displayWidth), - DISPLAY_HEIGHT(displayHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight) { - mProximityCharsArray = new uint32_t[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE]; - memcpy(mProximityCharsArray, proximityCharsArray, sizeof(mProximityCharsArray)); +ProximityInfo::ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth, + const int keyboardHeight, const int gridWidth, const int gridHeight, + const uint32_t *proximityCharsArray) + : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth), + KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), + CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), + CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight) { + const int len = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; + mProximityCharsArray = new uint32_t[len]; + if (DEBUG_PROXIMITY_INFO) { + LOGI("Create proximity info array %d", len); + } + memcpy(mProximityCharsArray, proximityCharsArray, len * sizeof(mProximityCharsArray[0])); } ProximityInfo::~ProximityInfo() { delete[] mProximityCharsArray; } + +inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const { + return (y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH) + * MAX_PROXIMITY_CHARS_SIZE; +} + +bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { + const int startIndex = getStartIndexFromCoordinates(x, y); + if (DEBUG_PROXIMITY_INFO) { + LOGI("hasSpaceProximity: index %d", startIndex); + } + for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { + if (DEBUG_PROXIMITY_INFO) { + LOGI("Index: %d", mProximityCharsArray[startIndex + i]); + } + if (mProximityCharsArray[startIndex + i] == KEYCODE_SPACE) { + return true; + } + } + return false; } +} // namespace latinime diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h index 54e995059..0f1201866 100644 --- a/native/src/proximity_info.h +++ b/native/src/proximity_info.h @@ -25,15 +25,20 @@ namespace latinime { class ProximityInfo { public: - ProximityInfo(int maxProximityCharsSize, int displayWidth, int displayHeight, int gridWidth, - int gridHeight, uint32_t const *proximityCharsArray); + ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth, + const int keybaordHeight, const int gridWidth, const int gridHeight, + const uint32_t *proximityCharsArray); ~ProximityInfo(); + bool hasSpaceProximity(const int x, const int y) const; private: - const int MAX_PROXIMITY_CHARS_SIZE; - const int DISPLAY_WIDTH; - const int DISPLAY_HEIGHT; + int getStartIndexFromCoordinates(const int x, const int y) const; + const int CELL_WIDTH; + const int CELL_HEIGHT; + const int KEYBOARD_WIDTH; + const int KEYBOARD_HEIGHT; const int GRID_WIDTH; const int GRID_HEIGHT; + const int MAX_PROXIMITY_CHARS_SIZE; uint32_t *mProximityCharsArray; }; }; // namespace latinime diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 17a87a708..3487d4f11 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -41,7 +41,8 @@ UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterM MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion), TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier), ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0), - BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(*mInputCodes)) { + BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(*mInputCodes)), + MAX_UMLAUT_SEARCH_DEPTH(DEFAULT_MAX_UMLAUT_SEARCH_DEPTH) { if (DEBUG_DICT) LOGI("UnigramDictionary - constructor"); } @@ -80,30 +81,37 @@ bool UnigramDictionary::isDigraph(const int* codes, const int i, const int codes void UnigramDictionary::getWordWithDigraphSuggestionsRec(const ProximityInfo *proximityInfo, const int *xcoordinates, const int* ycoordinates, const int *codesBuffer, const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain, - int* codesDest, unsigned short* outWords, int* frequencies) { - - for (int i = 0; i < codesRemain; ++i) { - if (isDigraph(codesSrc, i, codesRemain)) { - // Found a digraph. We will try both spellings. eg. the word is "pruefen" - - // Copy the word up to the first char of the digraph, then continue processing - // on the remaining part of the word, skipping the second char of the digraph. - // In our example, copy "pru" and continue running on "fen" - memcpy(codesDest, codesSrc, i * BYTES_IN_ONE_CHAR); - getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - codesBufferSize, flags, codesSrc + (i + 1) * MAX_PROXIMITY_CHARS, - codesRemain - i - 1, codesDest + i * MAX_PROXIMITY_CHARS, - outWords, frequencies); - - // Copy the second char of the digraph in place, then continue processing on - // the remaining part of the word. - // In our example, after "pru" in the buffer copy the "e", and continue running on "fen" - memcpy(codesDest + i * MAX_PROXIMITY_CHARS, codesSrc + i * MAX_PROXIMITY_CHARS, - BYTES_IN_ONE_CHAR); - getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - codesBufferSize, flags, codesSrc + i * MAX_PROXIMITY_CHARS, codesRemain - i, - codesDest + i * MAX_PROXIMITY_CHARS, outWords, frequencies); - return; + int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies) { + + if (currentDepth < MAX_UMLAUT_SEARCH_DEPTH) { + for (int i = 0; i < codesRemain; ++i) { + if (isDigraph(codesSrc, i, codesRemain)) { + // Found a digraph. We will try both spellings. eg. the word is "pruefen" + + // Copy the word up to the first char of the digraph, then continue processing + // on the remaining part of the word, skipping the second char of the digraph. + // In our example, copy "pru" and continue running on "fen" + // Make i the index of the second char of the digraph for simplicity. Forgetting + // to do that results in an infinite recursion so take care! + ++i; + memcpy(codesDest, codesSrc, i * BYTES_IN_ONE_CHAR); + getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, + codesBuffer, codesBufferSize, flags, + codesSrc + (i + 1) * MAX_PROXIMITY_CHARS, codesRemain - i - 1, + currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, outWords, + frequencies); + + // Copy the second char of the digraph in place, then continue processing on + // the remaining part of the word. + // In our example, after "pru" in the buffer copy the "e", and continue on "fen" + memcpy(codesDest + i * MAX_PROXIMITY_CHARS, codesSrc + i * MAX_PROXIMITY_CHARS, + BYTES_IN_ONE_CHAR); + getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, + codesBuffer, codesBufferSize, flags, codesSrc + i * MAX_PROXIMITY_CHARS, + codesRemain - i, currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, + outWords, frequencies); + return; + } } } @@ -128,13 +136,13 @@ int UnigramDictionary::getSuggestions(const ProximityInfo *proximityInfo, const { // Incrementally tune the word and try all possibilities int codesBuffer[getCodesBufferSize(codes, codesSize, MAX_PROXIMITY_CHARS)]; getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - codesSize, flags, codes, codesSize, codesBuffer, outWords, frequencies); + codesSize, flags, codes, codesSize, 0, codesBuffer, outWords, frequencies); } else { // Normal processing getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize, outWords, frequencies); } - PROF_START(6); + PROF_START(20); // Get the word count int suggestedWordsCount = 0; while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) { @@ -150,7 +158,7 @@ int UnigramDictionary::getSuggestions(const ProximityInfo *proximityInfo, const } } } - PROF_END(6); + PROF_END(20); PROF_CLOSE; return suggestedWordsCount; } @@ -164,12 +172,6 @@ void UnigramDictionary::getWordSuggestions(const ProximityInfo *proximityInfo, initSuggestions(codes, codesSize, outWords, frequencies); if (DEBUG_DICT) assert(codesSize == mInputLength); - if (DEBUG_PROXIMITY_INFO) { - for (int i = 0; i < codesSize; ++i) { - LOGI("Input[%d] x = %d, y = %d", i, xcoordinates[i], ycoordinates[i]); - } - } - const int MAX_DEPTH = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH); PROF_END(0); @@ -219,6 +221,25 @@ void UnigramDictionary::getWordSuggestions(const ProximityInfo *proximityInfo, } } PROF_END(5); + + PROF_START(6); + if (SUGGEST_WORDS_WITH_SPACE_PROXIMITY) { + // The first and last "mistyped spaces" are taken care of by excessive character handling + for (int i = 1; i < codesSize - 1; ++i) { + if (DEBUG_DICT) LOGI("--- Suggest words with proximity space %d", i); + const int x = xcoordinates[i]; + const int y = ycoordinates[i]; + if (DEBUG_PROXIMITY_INFO) + LOGI("Input[%d] x = %d, y = %d, has space proximity = %d", + i, x, y, proximityInfo->hasSpaceProximity(x, y)); + + if (proximityInfo->hasSpaceProximity(x, y)) { + getMistypedSpaceWords(mInputLength, i); + } + + } + } + PROF_END(6); } void UnigramDictionary::initSuggestions(const int *codes, const int codesSize, @@ -379,27 +400,31 @@ inline static void multiplyRate(const int rate, int *freq) { } } -bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) { - if (missingSpacePos <= 0 || missingSpacePos >= inputLength - || inputLength >= MAX_WORD_LENGTH) return false; - const int newWordLength = inputLength + 1; +bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength, + const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos, + const int secondWordLength) { + if (inputLength >= MAX_WORD_LENGTH) return false; + if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos + || firstWordStartPos < 0 || secondWordStartPos >= inputLength) + return false; + const int newWordLength = firstWordLength + secondWordLength + 1; // Allocating variable length array on stack unsigned short word[newWordLength]; - const int firstFreq = getBestWordFreq(0, missingSpacePos, mWord); + const int firstFreq = getBestWordFreq(firstWordStartPos, firstWordLength, mWord); if (DEBUG_DICT) LOGI("First freq: %d", firstFreq); if (firstFreq <= 0) return false; - for (int i = 0; i < missingSpacePos; ++i) { + for (int i = 0; i < firstWordLength; ++i) { word[i] = mWord[i]; } - const int secondFreq = getBestWordFreq(missingSpacePos, inputLength - missingSpacePos, mWord); + const int secondFreq = getBestWordFreq(secondWordStartPos, secondWordLength, mWord); if (DEBUG_DICT) LOGI("Second freq: %d", secondFreq); if (secondFreq <= 0) return false; - word[missingSpacePos] = SPACE; - for (int i = (missingSpacePos + 1); i < newWordLength; ++i) { - word[i] = mWord[i - missingSpacePos - 1]; + word[firstWordLength] = SPACE; + for (int i = (firstWordLength + 1); i < newWordLength; ++i) { + word[i] = mWord[i - firstWordLength - 1]; } int pairFreq = ((firstFreq + secondFreq) / 2); @@ -409,6 +434,17 @@ bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int mi return true; } +bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) { + return getSplitTwoWordsSuggestion( + inputLength, 0, missingSpacePos, missingSpacePos, inputLength - missingSpacePos); +} + +bool UnigramDictionary::getMistypedSpaceWords(const int inputLength, const int spaceProximityPos) { + return getSplitTwoWordsSuggestion( + inputLength, 0, spaceProximityPos, spaceProximityPos + 1, + inputLength - spaceProximityPos - 1); +} + // Keep this for comparing spec to new getWords void UnigramDictionary::getWordsOld(const int initialPos, const int inputLength, const int skipPos, const int excessivePos, const int transposedPos,int *nextLetters, diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index 2912cb0b7..ef820cba5 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -46,7 +46,7 @@ private: void getWordWithDigraphSuggestionsRec(const ProximityInfo *proximityInfo, const int *xcoordinates, const int* ycoordinates, const int *codesBuffer, const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain, - int* codesDest, unsigned short* outWords, int* frequencies); + int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies); void initSuggestions(const int *codes, const int codesSize, unsigned short *outWords, int *frequencies); void getSuggestionCandidates(const int skipPos, const int excessivePos, @@ -64,7 +64,11 @@ private: const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs, const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters, const int nextLettersSize); + bool getSplitTwoWordsSuggestion(const int inputLength, + const int firstWordStartPos, const int firstWordLength, + const int secondWordStartPos, const int secondWordLength); bool getMissingSpaceWords(const int inputLength, const int missingSpacePos); + bool getMistypedSpaceWords(const int inputLength, const int spaceProximityPos); // Keep getWordsOld for comparing performance between getWords and getWordsOld void getWordsOld(const int initialPos, const int inputLength, const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters, @@ -109,6 +113,7 @@ private: const int FULL_WORD_MULTIPLIER; const int ROOT_POS; const unsigned int BYTES_IN_ONE_CHAR; + const unsigned int MAX_UMLAUT_SEARCH_DEPTH; // Flags for special processing // Those *must* match the flags in BinaryDictionary.Flags.ALL_FLAGS in BinaryDictionary.java diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index a845acb9a..ed01a753b 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -73,6 +73,7 @@ public class SuggestHelper { final int[] codes = mKeyDetector.newCodeArray(); mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); word.add(c, codes, x, y); + return; } } word.add(c, new int[] { c }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); |