Use translation of fallback umlauts digraphs for German.
For German : handle "ae", "oe" and "ue" to be alternate forms for umlaut-bearing versions of "a", "o" and "u". Issue: 3275926 Change-Id: I056c707cdacc464ceab63be56c016c7f8439196cmain
parent
e59491460b
commit
c2bbc6a449
|
@ -65,6 +65,7 @@
|
|||
android:label="@string/subtype_mode_de_keyboard"
|
||||
android:imeSubtypeLocale="de"
|
||||
android:imeSubtypeMode="keyboard"
|
||||
android:imeSubtypeExtraValue="requiresGermanUmlautProcessing"
|
||||
/>
|
||||
<subtype android:icon="@drawable/ic_subtype_mic"
|
||||
android:label="@string/subtype_mode_de_voice"
|
||||
|
|
|
@ -58,6 +58,25 @@ public class BinaryDictionary extends Dictionary {
|
|||
private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS];
|
||||
|
||||
private final KeyboardSwitcher mKeyboardSwitcher = KeyboardSwitcher.getInstance();
|
||||
private final SubtypeSwitcher mSubtypeSwitcher = SubtypeSwitcher.getInstance();
|
||||
|
||||
private static class Flags {
|
||||
private static class FlagEntry {
|
||||
public final String mName;
|
||||
public final int mValue;
|
||||
public FlagEntry(String name, int value) {
|
||||
mName = name;
|
||||
mValue = value;
|
||||
}
|
||||
}
|
||||
public static final FlagEntry[] ALL_FLAGS = {
|
||||
// Here should reside all flags that trigger some special processing
|
||||
// These *must* match the definition in UnigramDictionary enum in
|
||||
// unigram_dictionary.h so please update both at the same time.
|
||||
new FlagEntry("requiresGermanUmlautProcessing", 0x1)
|
||||
};
|
||||
}
|
||||
private int mFlags = 0;
|
||||
|
||||
private BinaryDictionary() {
|
||||
}
|
||||
|
@ -91,6 +110,7 @@ public class BinaryDictionary extends Dictionary {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
sInstance.initFlags();
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
|
@ -109,16 +129,26 @@ public class BinaryDictionary extends Dictionary {
|
|||
return sInstance;
|
||||
}
|
||||
|
||||
private void initFlags() {
|
||||
int flags = 0;
|
||||
for (Flags.FlagEntry entry : Flags.ALL_FLAGS) {
|
||||
if (mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(entry.mName))
|
||||
flags |= entry.mValue;
|
||||
}
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
static {
|
||||
Utils.loadNativeLibrary();
|
||||
}
|
||||
|
||||
private native int openNative(String sourceDir, long dictOffset, long dictSize,
|
||||
int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
|
||||
int maxWords, int maxAlternatives);
|
||||
private native void closeNative(int dict);
|
||||
private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
|
||||
private native int getSuggestionsNative(int dict, int proximityInfo, int[] xCoordinates,
|
||||
int[] yCoordinates, int[] inputCodes, int codesSize, char[] outputChars,
|
||||
int[] yCoordinates, int[] inputCodes, int codesSize, int flags, char[] outputChars,
|
||||
int[] frequencies);
|
||||
private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
|
||||
int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
|
||||
|
@ -207,7 +237,7 @@ public class BinaryDictionary extends Dictionary {
|
|||
return getSuggestionsNative(
|
||||
mNativeDict, keyboard.getProximityInfo(),
|
||||
codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize,
|
||||
outputChars, frequencies);
|
||||
mFlags, outputChars, frequencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,10 +74,10 @@ public class SubtypeSwitcher {
|
|||
private InputMethodInfo mShortcutInputMethodInfo;
|
||||
private InputMethodSubtype mShortcutSubtype;
|
||||
private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
|
||||
private InputMethodSubtype mCurrentSubtype;
|
||||
private Locale mSystemLocale;
|
||||
private Locale mInputLocale;
|
||||
private String mInputLocaleStr;
|
||||
private String mMode;
|
||||
private VoiceInput mVoiceInput;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
@ -110,8 +110,7 @@ public class SubtypeSwitcher {
|
|||
mSystemLocale = null;
|
||||
mInputLocale = null;
|
||||
mInputLocaleStr = null;
|
||||
// Mode is initialized to KEYBOARD_MODE, in case that LatinIME can't obtain currentSubtype
|
||||
mMode = KEYBOARD_MODE;
|
||||
mCurrentSubtype = null;
|
||||
mAllEnabledSubtypesOfCurrentInputMethod = null;
|
||||
// TODO: Voice input should be created here
|
||||
mVoiceInput = null;
|
||||
|
@ -145,6 +144,7 @@ public class SubtypeSwitcher {
|
|||
|
||||
// Reload enabledSubtypes from the framework.
|
||||
private void updateEnabledSubtypes() {
|
||||
final String currentMode = getCurrentSubtypeMode();
|
||||
boolean foundCurrentSubtypeBecameDisabled = true;
|
||||
mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
|
||||
null, true);
|
||||
|
@ -157,7 +157,7 @@ public class SubtypeSwitcher {
|
|||
if (mLocaleSplitter.hasNext()) {
|
||||
mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next());
|
||||
}
|
||||
if (locale.equals(mInputLocaleStr) && mode.equals(mMode)) {
|
||||
if (locale.equals(mInputLocaleStr) && mode.equals(currentMode)) {
|
||||
foundCurrentSubtypeBecameDisabled = false;
|
||||
}
|
||||
if (KEYBOARD_MODE.equals(ims.getMode())) {
|
||||
|
@ -168,7 +168,7 @@ public class SubtypeSwitcher {
|
|||
&& mIsSystemLanguageSameAsInputLanguage);
|
||||
if (foundCurrentSubtypeBecameDisabled) {
|
||||
if (DBG) {
|
||||
Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + mMode);
|
||||
Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + currentMode);
|
||||
Log.w(TAG, "Last subtype was disabled. Update to the current one.");
|
||||
}
|
||||
updateSubtype(mImm.getCurrentInputMethodSubtype());
|
||||
|
@ -209,9 +209,10 @@ public class SubtypeSwitcher {
|
|||
public void updateSubtype(InputMethodSubtype newSubtype) {
|
||||
final String newLocale;
|
||||
final String newMode;
|
||||
final String oldMode = getCurrentSubtypeMode();
|
||||
if (newSubtype == null) {
|
||||
// Normally, newSubtype shouldn't be null. But just in case newSubtype was null,
|
||||
// fallback to the default locale and mode.
|
||||
// fallback to the default locale.
|
||||
Log.w(TAG, "Couldn't get the current subtype.");
|
||||
newLocale = "en_US";
|
||||
newMode = KEYBOARD_MODE;
|
||||
|
@ -220,8 +221,8 @@ public class SubtypeSwitcher {
|
|||
newMode = newSubtype.getMode();
|
||||
}
|
||||
if (DBG) {
|
||||
Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode
|
||||
+ ", from: " + mInputLocaleStr + ", " + mMode);
|
||||
Log.w(TAG, "Update subtype to:" + newLocale + "," + newSubtype.getMode()
|
||||
+ ", from: " + mInputLocaleStr + ", " + oldMode);
|
||||
}
|
||||
boolean languageChanged = false;
|
||||
if (!newLocale.equals(mInputLocaleStr)) {
|
||||
|
@ -231,13 +232,12 @@ public class SubtypeSwitcher {
|
|||
updateInputLocale(newLocale);
|
||||
}
|
||||
boolean modeChanged = false;
|
||||
String oldMode = mMode;
|
||||
if (!newMode.equals(mMode)) {
|
||||
if (mMode != null) {
|
||||
if (!newMode.equals(oldMode)) {
|
||||
if (oldMode != null) {
|
||||
modeChanged = true;
|
||||
}
|
||||
mMode = newMode;
|
||||
}
|
||||
mCurrentSubtype = newSubtype;
|
||||
|
||||
// If the old mode is voice input, we need to reset or cancel its status.
|
||||
// We cancel its status when we change mode, while we reset otherwise.
|
||||
|
@ -262,7 +262,7 @@ public class SubtypeSwitcher {
|
|||
triggerVoiceIME();
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Unknown subtype mode: " + mMode);
|
||||
Log.w(TAG, "Unknown subtype mode: " + newMode);
|
||||
if (VOICE_MODE.equals(oldMode) && mVoiceInput != null) {
|
||||
// We need to reset the voice input to release the resources and to reset its status
|
||||
// as it is not the current input mode.
|
||||
|
@ -483,7 +483,7 @@ public class SubtypeSwitcher {
|
|||
}
|
||||
|
||||
public boolean isKeyboardMode() {
|
||||
return KEYBOARD_MODE.equals(mMode);
|
||||
return KEYBOARD_MODE.equals(getCurrentSubtypeMode());
|
||||
}
|
||||
|
||||
|
||||
|
@ -506,7 +506,7 @@ public class SubtypeSwitcher {
|
|||
}
|
||||
|
||||
public boolean isVoiceMode() {
|
||||
return VOICE_MODE.equals(mMode);
|
||||
return null == mCurrentSubtype ? false : VOICE_MODE.equals(getCurrentSubtypeMode());
|
||||
}
|
||||
|
||||
private void triggerVoiceIME() {
|
||||
|
@ -572,6 +572,30 @@ public class SubtypeSwitcher {
|
|||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Other utility functions //
|
||||
/////////////////////////////
|
||||
|
||||
public String getCurrentSubtypeExtraValue() {
|
||||
// If null, return what an empty ExtraValue would return : the empty string.
|
||||
return null != mCurrentSubtype ? mCurrentSubtype.getExtraValue() : "";
|
||||
}
|
||||
|
||||
public boolean currentSubtypeContainsExtraValueKey(String key) {
|
||||
// If null, return what an empty ExtraValue would return : false.
|
||||
return null != mCurrentSubtype ? mCurrentSubtype.containsExtraValueKey(key) : false;
|
||||
}
|
||||
|
||||
public String getCurrentSubtypeExtraValueOf(String key) {
|
||||
// If null, return what an empty ExtraValue would return : null.
|
||||
return null != mCurrentSubtype ? mCurrentSubtype.getExtraValueOf(key) : null;
|
||||
}
|
||||
|
||||
public String getCurrentSubtypeMode() {
|
||||
return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE;
|
||||
}
|
||||
|
||||
|
||||
// A list of locales which are supported by default for voice input, unless we get a
|
||||
// different list from Gservices.
|
||||
private static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
|
||||
|
|
|
@ -126,7 +126,8 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object,
|
|||
|
||||
static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict,
|
||||
jint proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray,
|
||||
jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray) {
|
||||
jintArray inputArray, jint arraySize, jint flags,
|
||||
jcharArray outputArray, jintArray frequencyArray) {
|
||||
Dictionary *dictionary = (Dictionary*)dict;
|
||||
if (!dictionary) return 0;
|
||||
ProximityInfo *pInfo = (ProximityInfo*)proximityInfo;
|
||||
|
@ -140,7 +141,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object,
|
|||
jchar *outputChars = env->GetCharArrayElements(outputArray, NULL);
|
||||
|
||||
int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes,
|
||||
arraySize, (unsigned short*) outputChars, frequencies);
|
||||
arraySize, flags, (unsigned short*) outputChars, frequencies);
|
||||
|
||||
env->ReleaseIntArrayElements(frequencyArray, frequencies, 0);
|
||||
env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT);
|
||||
|
@ -213,7 +214,7 @@ static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint di
|
|||
static JNINativeMethod sMethods[] = {
|
||||
{"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open},
|
||||
{"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close},
|
||||
{"getSuggestionsNative", "(II[I[I[II[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions},
|
||||
{"getSuggestionsNative", "(II[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions},
|
||||
{"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord},
|
||||
{"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}
|
||||
};
|
||||
|
|
|
@ -55,4 +55,15 @@ static inline void LOGI_S16_PLUS(unsigned short* string, const unsigned int leng
|
|||
// usleep(10);
|
||||
}
|
||||
|
||||
static inline void printDebug(const char* tag, int* codes, int codesSize, int MAX_PROXIMITY_CHARS) {
|
||||
unsigned char *buf = (unsigned char*)malloc((1 + codesSize) * sizeof(*buf));
|
||||
|
||||
buf[codesSize] = 0;
|
||||
while (--codesSize >= 0)
|
||||
buf[codesSize] = (unsigned char)codes[codesSize * MAX_PROXIMITY_CHARS];
|
||||
LOGI("%s, WORD = %s", tag, buf);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
#endif // LATINIME_DEBUG_H
|
||||
|
|
|
@ -29,9 +29,9 @@ public:
|
|||
Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler,
|
||||
int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
|
||||
int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates,
|
||||
int *codes, int codesSize, unsigned short *outWords, int *frequencies) {
|
||||
int *codes, int codesSize, int flags, unsigned short *outWords, int *frequencies) {
|
||||
return mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
|
||||
codesSize, outWords, frequencies);
|
||||
codesSize, flags, outWords, frequencies);
|
||||
}
|
||||
|
||||
// TODO: Call mBigramDictionary instead of mUnigramDictionary
|
||||
|
|
|
@ -29,20 +29,136 @@
|
|||
|
||||
namespace latinime {
|
||||
|
||||
const UnigramDictionary::digraph_t UnigramDictionary::GERMAN_UMLAUT_DIGRAPHS[] =
|
||||
{ { 'a', 'e' },
|
||||
{ 'o', 'e' },
|
||||
{ 'u', 'e' } };
|
||||
|
||||
UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterMultiplier,
|
||||
int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars,
|
||||
const bool isLatestDictVersion)
|
||||
: DICT(dict), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords),
|
||||
MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion),
|
||||
TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier),
|
||||
ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0) {
|
||||
ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0),
|
||||
BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(*mInputCodes)) {
|
||||
if (DEBUG_DICT) LOGI("UnigramDictionary - constructor");
|
||||
}
|
||||
|
||||
UnigramDictionary::~UnigramDictionary() {}
|
||||
|
||||
int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates,
|
||||
int *ycoordinates, int *codes, int codesSize, unsigned short *outWords, int *frequencies) {
|
||||
static inline unsigned int getCodesBufferSize(const int* codes, const int codesSize,
|
||||
const int MAX_PROXIMITY_CHARS) {
|
||||
return sizeof(*codes) * MAX_PROXIMITY_CHARS * codesSize;
|
||||
}
|
||||
|
||||
bool UnigramDictionary::isDigraph(const int* codes, const int i, const int codesSize) const {
|
||||
|
||||
// There can't be a digraph if we don't have at least 2 characters to examine
|
||||
if (i + 2 > codesSize) return false;
|
||||
|
||||
// Search for the first char of some digraph
|
||||
int lastDigraphIndex = -1;
|
||||
const int thisChar = codes[i * MAX_PROXIMITY_CHARS];
|
||||
for (lastDigraphIndex = sizeof(GERMAN_UMLAUT_DIGRAPHS) / sizeof(GERMAN_UMLAUT_DIGRAPHS[0]) - 1;
|
||||
lastDigraphIndex >= 0; --lastDigraphIndex) {
|
||||
if (thisChar == GERMAN_UMLAUT_DIGRAPHS[lastDigraphIndex].first) break;
|
||||
}
|
||||
// No match: return early
|
||||
if (lastDigraphIndex < 0) return false;
|
||||
|
||||
// It's an interesting digraph if the second char matches too.
|
||||
return GERMAN_UMLAUT_DIGRAPHS[lastDigraphIndex].second == codes[(i + 1) * MAX_PROXIMITY_CHARS];
|
||||
}
|
||||
|
||||
// Mostly the same arguments as the non-recursive version, except:
|
||||
// codes is the original value. It points to the start of the work buffer, and gets passed as is.
|
||||
// codesSize is the size of the user input (thus, it is the size of codesSrc).
|
||||
// codesDest is the current point in the work buffer.
|
||||
// codesSrc is the current point in the user-input, original, content-unmodified buffer.
|
||||
// codesRemain is the remaining size in codesSrc.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// If we come here, we hit the end of the word: let's check it against the dictionary.
|
||||
// In our example, we'll come here once for "prufen" and then once for "pruefen".
|
||||
// If the word contains several digraphs, we'll come it for the product of them.
|
||||
// eg. if the word is "ueberpruefen" we'll test, in order, against
|
||||
// "uberprufen", "uberpruefen", "ueberprufen", "ueberpruefen".
|
||||
const unsigned int remainingBytes = BYTES_IN_ONE_CHAR * codesRemain;
|
||||
if (0 != remainingBytes)
|
||||
memcpy(codesDest, codesSrc, remainingBytes);
|
||||
|
||||
getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
|
||||
(codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, outWords, frequencies);
|
||||
}
|
||||
|
||||
int UnigramDictionary::getSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
|
||||
const int *ycoordinates, const int *codes, const int codesSize, const int flags,
|
||||
unsigned short *outWords, int *frequencies) {
|
||||
|
||||
if (REQUIRES_GERMAN_UMLAUT_PROCESSING & flags)
|
||||
{ // 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);
|
||||
} else { // Normal processing
|
||||
getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize,
|
||||
outWords, frequencies);
|
||||
}
|
||||
|
||||
PROF_START(6);
|
||||
// Get the word count
|
||||
int suggestedWordsCount = 0;
|
||||
while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
|
||||
suggestedWordsCount++;
|
||||
}
|
||||
|
||||
if (DEBUG_DICT) {
|
||||
LOGI("Returning %d words", suggestedWordsCount);
|
||||
LOGI("Next letters: ");
|
||||
for (int k = 0; k < NEXT_LETTERS_SIZE; k++) {
|
||||
if (mNextLettersFrequency[k] > 0) {
|
||||
LOGI("%c = %d,", k, mNextLettersFrequency[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
PROF_END(6);
|
||||
PROF_CLOSE;
|
||||
return suggestedWordsCount;
|
||||
}
|
||||
|
||||
void UnigramDictionary::getWordSuggestions(const ProximityInfo *proximityInfo,
|
||||
const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize,
|
||||
unsigned short *outWords, int *frequencies) {
|
||||
|
||||
PROF_OPEN;
|
||||
PROF_START(0);
|
||||
initSuggestions(codes, codesSize, outWords, frequencies);
|
||||
|
@ -103,30 +219,10 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, int *xcoordi
|
|||
}
|
||||
}
|
||||
PROF_END(5);
|
||||
|
||||
PROF_START(6);
|
||||
// Get the word count
|
||||
int suggestedWordsCount = 0;
|
||||
while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
|
||||
suggestedWordsCount++;
|
||||
}
|
||||
|
||||
if (DEBUG_DICT) {
|
||||
LOGI("Returning %d words", suggestedWordsCount);
|
||||
LOGI("Next letters: ");
|
||||
for (int k = 0; k < NEXT_LETTERS_SIZE; k++) {
|
||||
if (mNextLettersFrequency[k] > 0) {
|
||||
LOGI("%c = %d,", k, mNextLettersFrequency[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
PROF_END(6);
|
||||
PROF_CLOSE;
|
||||
return suggestedWordsCount;
|
||||
}
|
||||
|
||||
void UnigramDictionary::initSuggestions(int *codes, int codesSize, unsigned short *outWords,
|
||||
int *frequencies) {
|
||||
void UnigramDictionary::initSuggestions(const int *codes, const int codesSize,
|
||||
unsigned short *outWords, int *frequencies) {
|
||||
if (DEBUG_DICT) LOGI("initSuggest");
|
||||
mFrequencies = frequencies;
|
||||
mOutputChars = outWords;
|
||||
|
@ -204,7 +300,7 @@ bool UnigramDictionary::sameAsTyped(unsigned short *word, int length) {
|
|||
if (length != mInputLength) {
|
||||
return false;
|
||||
}
|
||||
int *inputCodes = mInputCodes;
|
||||
const int *inputCodes = mInputCodes;
|
||||
while (length--) {
|
||||
if ((unsigned int) *inputCodes != (unsigned int) *word) {
|
||||
return false;
|
||||
|
@ -423,7 +519,7 @@ inline bool UnigramDictionary::existsAdjacentProximityChars(const int inputIndex
|
|||
const int currentChar = *getInputCharsAt(inputIndex);
|
||||
const int leftIndex = inputIndex - 1;
|
||||
if (leftIndex >= 0) {
|
||||
int *leftChars = getInputCharsAt(leftIndex);
|
||||
const int *leftChars = getInputCharsAt(leftIndex);
|
||||
int i = 0;
|
||||
while (leftChars[i] > 0 && i < MAX_PROXIMITY_CHARS) {
|
||||
if (leftChars[i++] == currentChar) return true;
|
||||
|
@ -431,7 +527,7 @@ inline bool UnigramDictionary::existsAdjacentProximityChars(const int inputIndex
|
|||
}
|
||||
const int rightIndex = inputIndex + 1;
|
||||
if (rightIndex < inputLength) {
|
||||
int *rightChars = getInputCharsAt(rightIndex);
|
||||
const int *rightChars = getInputCharsAt(rightIndex);
|
||||
int i = 0;
|
||||
while (rightChars[i] > 0 && i < MAX_PROXIMITY_CHARS) {
|
||||
if (rightChars[i++] == currentChar) return true;
|
||||
|
@ -523,7 +619,7 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth
|
|||
*newDiffs = diffs;
|
||||
*newInputIndex = inputIndex;
|
||||
} else {
|
||||
int *currentChars = getInputCharsAt(inputIndex);
|
||||
const int *currentChars = getInputCharsAt(inputIndex);
|
||||
|
||||
if (transposedPos >= 0) {
|
||||
if (inputIndex == transposedPos) currentChars += MAX_PROXIMITY_CHARS;
|
||||
|
|
|
@ -33,12 +33,22 @@ class UnigramDictionary {
|
|||
public:
|
||||
UnigramDictionary(const unsigned char *dict, int typedLetterMultipler, int fullWordMultiplier,
|
||||
int maxWordLength, int maxWords, int maxProximityChars, const bool isLatestDictVersion);
|
||||
int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates,
|
||||
int *codes, int codesSize, unsigned short *outWords, int *frequencies);
|
||||
int getSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
|
||||
const int *ycoordinates, const int *codes, const int codesSize, const int flags,
|
||||
unsigned short *outWords, int *frequencies);
|
||||
~UnigramDictionary();
|
||||
|
||||
private:
|
||||
void initSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies);
|
||||
void getWordSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
|
||||
const int *ycoordinates, const int *codes, const int codesSize,
|
||||
unsigned short *outWords, int *frequencies);
|
||||
bool isDigraph(const int* codes, const int i, const int codesSize) const;
|
||||
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);
|
||||
void initSuggestions(const int *codes, const int codesSize, unsigned short *outWords,
|
||||
int *frequencies);
|
||||
void getSuggestionCandidates(const int skipPos, const int excessivePos,
|
||||
const int transposedPos, int *nextLetters, const int nextLettersSize,
|
||||
const int maxDepth);
|
||||
|
@ -86,7 +96,7 @@ private:
|
|||
const int startInputIndex, const int depth, unsigned short *word,
|
||||
int *newChildPosition, int *newCount, bool *newTerminal, int *newFreq, int *siblingPos);
|
||||
bool existsAdjacentProximityChars(const int inputIndex, const int inputLength);
|
||||
inline int* getInputCharsAt(const int index) {
|
||||
inline const int* getInputCharsAt(const int index) {
|
||||
return mInputCodes + (index * MAX_PROXIMITY_CHARS);
|
||||
}
|
||||
const unsigned char *DICT;
|
||||
|
@ -97,10 +107,20 @@ private:
|
|||
const int TYPED_LETTER_MULTIPLIER;
|
||||
const int FULL_WORD_MULTIPLIER;
|
||||
const int ROOT_POS;
|
||||
const unsigned int BYTES_IN_ONE_CHAR;
|
||||
|
||||
// Flags for special processing
|
||||
// Those *must* match the flags in BinaryDictionary.Flags.ALL_FLAGS in BinaryDictionary.java
|
||||
// or something very bad (like, the apocalypse) will happen.
|
||||
// Please update both at the same time.
|
||||
enum {
|
||||
REQUIRES_GERMAN_UMLAUT_PROCESSING = 0x1
|
||||
};
|
||||
static const struct digraph_t { int first; int second; } GERMAN_UMLAUT_DIGRAPHS[];
|
||||
|
||||
int *mFrequencies;
|
||||
unsigned short *mOutputChars;
|
||||
int *mInputCodes;
|
||||
const int *mInputCodes;
|
||||
int mInputLength;
|
||||
// MAX_WORD_LENGTH_INTERNAL must be bigger than MAX_WORD_LENGTH
|
||||
unsigned short mWord[MAX_WORD_LENGTH_INTERNAL];
|
||||
|
|
Loading…
Reference in New Issue