diff options
Diffstat (limited to 'native/jni/src')
23 files changed, 479 insertions, 201 deletions
diff --git a/native/jni/src/additional_proximity_chars.cpp b/native/jni/src/additional_proximity_chars.cpp index de8764678..f59492741 100644 --- a/native/jni/src/additional_proximity_chars.cpp +++ b/native/jni/src/additional_proximity_chars.cpp @@ -17,7 +17,9 @@ #include "additional_proximity_chars.h" namespace latinime { -const std::string AdditionalProximityChars::LOCALE_EN_US("en"); +// TODO: Stop using hardcoded additional proximity characters. +// TODO: Have proximity character informations in each language's binary dictionary. +const char *AdditionalProximityChars::LOCALE_EN_US = "en"; const int32_t AdditionalProximityChars::EN_US_ADDITIONAL_A[EN_US_ADDITIONAL_A_SIZE] = { 'e', 'i', 'o', 'u' diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h index ba76cfced..1fe996d0d 100644 --- a/native/jni/src/additional_proximity_chars.h +++ b/native/jni/src/additional_proximity_chars.h @@ -17,8 +17,8 @@ #ifndef LATINIME_ADDITIONAL_PROXIMITY_CHARS_H #define LATINIME_ADDITIONAL_PROXIMITY_CHARS_H +#include <cstring> #include <stdint.h> -#include <string> #include "defines.h" @@ -27,7 +27,7 @@ namespace latinime { class AdditionalProximityChars { private: DISALLOW_IMPLICIT_CONSTRUCTORS(AdditionalProximityChars); - static const std::string LOCALE_EN_US; + static const char *LOCALE_EN_US; static const int EN_US_ADDITIONAL_A_SIZE = 4; static const int32_t EN_US_ADDITIONAL_A[]; static const int EN_US_ADDITIONAL_E_SIZE = 4; @@ -39,14 +39,15 @@ class AdditionalProximityChars { static const int EN_US_ADDITIONAL_U_SIZE = 4; static const int32_t EN_US_ADDITIONAL_U[]; - static bool isEnLocale(const std::string *locale_str) { - return locale_str && locale_str->size() >= LOCALE_EN_US.size() - && LOCALE_EN_US.compare(0, LOCALE_EN_US.size(), *locale_str); + static bool isEnLocale(const char *localeStr) { + const size_t LOCALE_EN_US_SIZE = strlen(LOCALE_EN_US); + return localeStr && strlen(localeStr) >= LOCALE_EN_US_SIZE + && strncmp(localeStr, LOCALE_EN_US, LOCALE_EN_US_SIZE) == 0; } public: - static int getAdditionalCharsSize(const std::string *locale_str, const int32_t c) { - if (!isEnLocale(locale_str)) { + static int getAdditionalCharsSize(const char *localeStr, const int32_t c) { + if (!isEnLocale(localeStr)) { return 0; } switch(c) { @@ -65,8 +66,8 @@ class AdditionalProximityChars { } } - static const int32_t *getAdditionalChars(const std::string *locale_str, const int32_t c) { - if (!isEnLocale(locale_str)) { + static const int32_t *getAdditionalChars(const char *localeStr, const int32_t c) { + if (!isEnLocale(localeStr)) { return 0; } switch(c) { @@ -84,10 +85,6 @@ class AdditionalProximityChars { return 0; } } - - static bool hasAdditionalChars(const std::string *locale_str, const int32_t c) { - return getAdditionalCharsSize(locale_str, c) > 0; - } }; } // namespace latinime #endif // LATINIME_ADDITIONAL_PROXIMITY_CHARS_H diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 220171127..f1d538095 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -60,15 +60,15 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ AKLOGI("Bigram: InsertAt -> %d MAX_PREDICTIONS: %d", insertAt, MAX_PREDICTIONS); } if (insertAt < MAX_PREDICTIONS) { - memmove((char*) bigramFreq + (insertAt + 1) * sizeof(bigramFreq[0]), - (char*) bigramFreq + insertAt * sizeof(bigramFreq[0]), - (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramFreq[0])); + memmove(bigramFreq + (insertAt + 1), + bigramFreq + insertAt, + (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramFreq[0])); bigramFreq[insertAt] = frequency; outputTypes[insertAt] = Dictionary::KIND_PREDICTION; - memmove((char*) bigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short), - (char*) bigramChars + (insertAt ) * MAX_WORD_LENGTH * sizeof(short), - (MAX_PREDICTIONS - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH); - unsigned short *dest = bigramChars + (insertAt ) * MAX_WORD_LENGTH; + memmove(bigramChars + (insertAt + 1) * MAX_WORD_LENGTH, + bigramChars + insertAt * MAX_WORD_LENGTH, + (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramChars[0]) * MAX_WORD_LENGTH); + unsigned short *dest = bigramChars + insertAt * MAX_WORD_LENGTH; while (length--) { *dest++ = *word++; } diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index 2ee4077c1..4cabc8404 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -52,6 +52,8 @@ class BinaryFormat { // Mask for attribute frequency, stored on 4 bits inside the flags byte. static const int MASK_ATTRIBUTE_FREQUENCY = 0x0F; + // The numeric value of the shortcut frequency that means 'whitelist'. + static const int WHITELIST_SHORTCUT_FREQUENCY = 15; // Mask and flags for attribute address type selection. static const int MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30; @@ -99,6 +101,7 @@ class BinaryFormat { static bool hasChildrenInFlags(const uint8_t flags); static int getAttributeAddressAndForwardPointer(const uint8_t *const dict, const uint8_t flags, int *pos); + static int getAttributeFrequencyFromFlags(const int flags); static int getTerminalPosition(const uint8_t *const root, const int32_t *const inWord, const int length, const bool forceLowerCaseSearch); static int getWordAtAddress(const uint8_t *const root, const int address, const int maxDepth, @@ -340,6 +343,10 @@ inline int BinaryFormat::getAttributeAddressAndForwardPointer(const uint8_t *con } } +inline int BinaryFormat::getAttributeFrequencyFromFlags(const int flags) { + return flags & MASK_ATTRIBUTE_FREQUENCY; +} + // This function gets the byte position of the last chargroup of the exact matching word in the // dictionary. If no match is found, it returns NOT_VALID_WORD. inline int BinaryFormat::getTerminalPosition(const uint8_t *const root, diff --git a/native/jni/src/char_utils.cpp b/native/jni/src/char_utils.cpp index 45d49b087..223291f60 100644 --- a/native/jni/src/char_utils.cpp +++ b/native/jni/src/char_utils.cpp @@ -885,16 +885,16 @@ static const struct LatinCapitalSmallPair SORTED_CHAR_MAP[] = { }; static int compare_pair_capital(const void *a, const void *b) { - return (int)(*(unsigned short *)a) - - (int)((struct LatinCapitalSmallPair*)b)->capital; + return static_cast<int>(*static_cast<const unsigned short *>(a)) + - static_cast<int>((static_cast<const struct LatinCapitalSmallPair *>(b))->capital); } unsigned short latin_tolower(unsigned short c) { struct LatinCapitalSmallPair *p = - (struct LatinCapitalSmallPair *)bsearch(&c, SORTED_CHAR_MAP, + static_cast<struct LatinCapitalSmallPair *>(bsearch(&c, SORTED_CHAR_MAP, sizeof(SORTED_CHAR_MAP) / sizeof(SORTED_CHAR_MAP[0]), sizeof(SORTED_CHAR_MAP[0]), - compare_pair_capital); + compare_pair_capital)); return p ? p->small : c; } } // namespace latinime diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp index ea4bddae2..e55da0113 100644 --- a/native/jni/src/correction.cpp +++ b/native/jni/src/correction.cpp @@ -154,11 +154,13 @@ void Correction::checkState() { if (mSkipPos >= 0) ++inputCount; if (mExcessivePos >= 0) ++inputCount; if (mTransposedPos >= 0) ++inputCount; - // TODO: remove this assert - assert(inputCount <= 1); } } +bool Correction::sameAsTyped() { + return mProximityInfoState.sameAsTyped(mWord, mOutputIndex); +} + int Correction::getFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray, const int wordCount, const bool isSpaceProximity, const unsigned short *word) { return Correction::RankingAlgorithm::calcFreqForSplitMultipleWords(freqArray, wordLengthArray, @@ -1094,7 +1096,7 @@ int Correction::RankingAlgorithm::editDistance(const unsigned short *before, // In dictionary.cpp, getSuggestion() method, // suggestion scores are computed using the below formula. // original score -// := pow(mTypedLetterMultiplier (this is defined 2), +// := powf(mTypedLetterMultiplier (this is defined 2), // (the number of matched characters between typed word and suggested word)) // * (individual word's score which defined in the unigram dictionary, // and this score is defined in range [0, 255].) @@ -1106,11 +1108,11 @@ int Correction::RankingAlgorithm::editDistance(const unsigned short *before, // capitalization, then treat it as if the score was 255. // - If before.length() == after.length() // => multiply by mFullWordMultiplier (this is defined 2)) -// So, maximum original score is pow(2, min(before.length(), after.length())) * 255 * 2 * 1.2 +// So, maximum original score is powf(2, min(before.length(), after.length())) * 255 * 2 * 1.2 // For historical reasons we ignore the 1.2 modifier (because the measure for a good // autocorrection threshold was done at a time when it didn't exist). This doesn't change // the result. -// So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2. +// So, we can normalize original score by dividing powf(2, min(b.l(),a.l())) * 255 * 2. /* static */ float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short *before, @@ -1132,7 +1134,7 @@ float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short *be } const float maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE - * pow(static_cast<float>(TYPED_LETTER_MULTIPLIER), + * powf(static_cast<float>(TYPED_LETTER_MULTIPLIER), static_cast<float>(min(beforeLength, afterLength - spaceCount))) * FULL_WORD_MULTIPLIER; diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h index 81623a46b..57e7b7189 100644 --- a/native/jni/src/correction.h +++ b/native/jni/src/correction.h @@ -105,6 +105,7 @@ class Correction { const int spaceProximityPos, const int missingSpacePos, const bool useFullEditDistance, const bool doAutoCompletion, const int maxErrors); void checkState(); + bool sameAsTyped(); bool initProcessState(const int index); int getInputIndex(); diff --git a/native/jni/src/debug.h b/native/jni/src/debug.h index 2168d6672..4e2164014 100644 --- a/native/jni/src/debug.h +++ b/native/jni/src/debug.h @@ -58,11 +58,12 @@ static inline void LOGI_S16_PLUS(unsigned short *string, const unsigned int leng } 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)); + unsigned char *buf = static_cast<unsigned char *>(malloc((1 + codesSize) * sizeof(*buf))); buf[codesSize] = 0; - while (--codesSize >= 0) - buf[codesSize] = (unsigned char)codes[codesSize * MAX_PROXIMITY_CHARS]; + while (--codesSize >= 0) { + buf[codesSize] = static_cast<unsigned char>(codes[codesSize * MAX_PROXIMITY_CHARS]); + } AKLOGI("%s, WORD = %s", tag, buf); free(buf); diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index 31dd61e30..484fc6bde 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -265,6 +265,9 @@ static inline void prof_out(void) { // This must be equal to ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE in KeyDetector.java #define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 +// Assuming locale strings such as en_US, sr-Latn etc. +#define MAX_LOCALE_STRING_LENGTH 10 + // Word limit for sub queues used in WordsPriorityQueuePool. Sub queues are temporary queues used // for better performance. // Holds up to 1 candidate for each word diff --git a/native/jni/src/dic_traverse_wrapper.cpp b/native/jni/src/dic_traverse_wrapper.cpp new file mode 100644 index 000000000..1f7dcbfb2 --- /dev/null +++ b/native/jni/src/dic_traverse_wrapper.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LatinIME: jni: Session" + +#include "dic_traverse_wrapper.h" + +namespace latinime { +void *(*DicTraverseWrapper::sDicTraverseSessionFactoryMethod)(JNIEnv *env, jstring locale) = 0; +void (*DicTraverseWrapper::sDicTraverseSessionReleaseMethod)(void *) = 0; +void (*DicTraverseWrapper::sDicTraverseSessionInitMethod)( + void *, Dictionary *, const int *, const int) = 0; +} // namespace latinime diff --git a/native/jni/src/dic_traverse_wrapper.h b/native/jni/src/dic_traverse_wrapper.h new file mode 100644 index 000000000..8396d0027 --- /dev/null +++ b/native/jni/src/dic_traverse_wrapper.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_DIC_TRAVERSE_WRAPPER_H +#define LATINIME_DIC_TRAVERSE_WRAPPER_H + +#include <stdint.h> + +#include "defines.h" +#include "jni.h" + +namespace latinime { +class Dictionary; +// TODO: Remove +class DicTraverseWrapper { + public: + static void *getDicTraverseSession(JNIEnv *env, jstring locale) { + if (sDicTraverseSessionFactoryMethod) { + return sDicTraverseSessionFactoryMethod(env, locale); + } + return 0; + } + static void initDicTraverseSession(void *traverseSession, + Dictionary *dictionary, const int *prevWord, const int prevWordLength) { + if (sDicTraverseSessionInitMethod) { + sDicTraverseSessionInitMethod(traverseSession, dictionary, prevWord, prevWordLength); + } + } + static void releaseDicTraverseSession(void *traverseSession) { + if (sDicTraverseSessionReleaseMethod) { + sDicTraverseSessionReleaseMethod(traverseSession); + } + } + static void setTraverseSessionFactoryMethod( + void *(*factoryMethod)(JNIEnv *env, jstring locale)) { + sDicTraverseSessionFactoryMethod = factoryMethod; + } + static void setTraverseSessionInitMethod( + void (*initMethod)(void *, Dictionary *, const int *, const int)) { + sDicTraverseSessionInitMethod = initMethod; + } + static void setTraverseSessionReleaseMethod(void (*releaseMethod)(void *)) { + sDicTraverseSessionReleaseMethod = releaseMethod; + } + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseWrapper); + static void *(*sDicTraverseSessionFactoryMethod)(JNIEnv *, jstring); + static void (*sDicTraverseSessionInitMethod)(void *, Dictionary *, const int *, const int); + static void (*sDicTraverseSessionReleaseMethod)(void *); +}; +int register_DicTraverseSession(JNIEnv *env); +} // namespace latinime +#endif // LATINIME_DIC_TRAVERSE_WRAPPER_H diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index ee55cfa60..158c3fb22 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -22,6 +22,7 @@ #include "binary_format.h" #include "defines.h" #include "dictionary.h" +#include "dic_traverse_wrapper.h" #include "gesture_decoder_wrapper.h" #include "unigram_dictionary.h" @@ -31,8 +32,9 @@ namespace latinime { Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords, int maxPredictions) - : mDict((unsigned char*) dict), mDictSize(dictSize), - mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust) { + : mDict(static_cast<unsigned char *>(dict)), + mOffsetDict((static_cast<unsigned char *>(dict)) + BinaryFormat::getHeaderSize(mDict)), + mDictSize(dictSize), mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust) { if (DEBUG_DICT) { if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) { AKLOGI("Max word length (%d) is greater than %d", @@ -40,14 +42,11 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, AKLOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF)); } } - const unsigned int headerSize = BinaryFormat::getHeaderSize(mDict); const unsigned int options = BinaryFormat::getFlags(mDict); - mUnigramDictionary = new UnigramDictionary(mDict + headerSize, typedLetterMultiplier, + mUnigramDictionary = new UnigramDictionary(mOffsetDict, typedLetterMultiplier, fullWordMultiplier, maxWordLength, maxWords, options); - mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength, maxPredictions); + mBigramDictionary = new BigramDictionary(mOffsetDict, maxWordLength, maxPredictions); mGestureDecoder = new GestureDecoderWrapper(maxWordLength, maxWords); - mGestureDecoder->setDict(mUnigramDictionary, mBigramDictionary, - mDict + headerSize /* dict root */, 0 /* root pos */); } Dictionary::~Dictionary() { @@ -56,16 +55,18 @@ Dictionary::~Dictionary() { delete mGestureDecoder; } -int Dictionary::getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, - int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, +int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, + int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, + int *codes, int codesSize, int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture, bool useFullEditDistance, unsigned short *outWords, int *frequencies, int *spaceIndices, int *outputTypes) { int result = 0; if (isGesture) { - mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); - result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates, - times, pointerIds, codes, codesSize, commitPoint, + DicTraverseWrapper::initDicTraverseSession( + traverseSession, this, prevWordChars, prevWordLength); + result = mGestureDecoder->getSuggestions(proximityInfo, traverseSession, + xcoordinates, ycoordinates, times, pointerIds, codes, codesSize, commitPoint, outWords, frequencies, spaceIndices, outputTypes); if (DEBUG_DICT) { DUMP_RESULT(outWords, frequencies, 18 /* MAX_WORDS */, MAX_WORD_LENGTH_INTERNAL); diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index ab238c824..fd9e77011 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -44,9 +44,9 @@ class Dictionary { Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, int maxWords, int maxPredictions); - int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, - int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, - int prevWordLength, int commitPoint, bool isGesture, + int getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, int *xcoordinates, + int *ycoordinates, int *times, int *pointerIds, int *codes, int codesSize, + int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture, bool useFullEditDistance, unsigned short *outWords, int *frequencies, int *spaceIndices, int *outputTypes); @@ -55,7 +55,12 @@ class Dictionary { int getFrequency(const int32_t *word, int length) const; bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const; - void *getDict() const { return (void *)mDict; } + const uint8_t *getDict() const { // required to release dictionary buffer + return mDict; + } + const uint8_t *getOffsetDict() const { + return mOffsetDict; + } int getDictSize() const { return mDictSize; } int getMmapFd() const { return mMmapFd; } int getDictBufAdjust() const { return mDictBufAdjust; } @@ -67,7 +72,8 @@ class Dictionary { private: DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary); - const unsigned char *mDict; + const uint8_t *mDict; + const uint8_t *mOffsetDict; // Used only for the mmap version of dictionary loading, but we use these as dummy variables // also for the malloc version. @@ -85,8 +91,9 @@ class Dictionary { inline int Dictionary::wideStrLen(unsigned short *str) { if (!str) return 0; unsigned short *end = str; - while (*end) + while (*end) { end++; + } return end - str; } } // namespace latinime diff --git a/native/jni/src/geometry_utils.h b/native/jni/src/geometry_utils.h new file mode 100644 index 000000000..146eb8055 --- /dev/null +++ b/native/jni/src/geometry_utils.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_GEOMETRY_UTILS_H +#define LATINIME_GEOMETRY_UTILS_H + +#include <cmath> + +#define MAX_DISTANCE 10000000 +#define MAX_PATHS 2 + +#define DEBUG_DECODER false + +#define M_PI_F 3.14159265f + +namespace latinime { + +static inline float squareFloat(float x) { + return x * x; +} + +static inline float getSquaredDistanceFloat(float x1, float y1, float x2, float y2) { + return squareFloat(x1 - x2) + squareFloat(y1 - y2); +} + +static inline float getDistanceFloat(float x1, float y1, float x2, float y2) { + return hypotf(x1 - x2, y1 - y2); +} + +static inline int getDistanceInt(int x1, int y1, int x2, int y2) { + return static_cast<int>(getDistanceFloat(static_cast<float>(x1), static_cast<float>(y1), + static_cast<float>(x2), static_cast<float>(y2))); +} + +static inline float getAngle(int x1, int y1, int x2, int y2) { + const int dx = x1 - x2; + const int dy = y1 - y2; + if (dx == 0 && dy == 0) return 0; + return atan2f(static_cast<float>(dy), static_cast<float>(dx)); +} + +static inline float getAngleDiff(float a1, float a2) { + const float diff = fabsf(a1 - a2); + if (diff > M_PI_F) { + return 2.0f * M_PI_F - diff; + } + return diff; +} + +// static float pointToLineSegSquaredDistanceFloat( +// float x, float y, float x1, float y1, float x2, float y2) { +// float A = x - x1; +// float B = y - y1; +// float C = x2 - x1; +// float D = y2 - y1; +// return fabsf(A * D - C * B) / sqrtf(C * C + D * D); +// } + +static inline float pointToLineSegSquaredDistanceFloat( + float x, float y, float x1, float y1, float x2, float y2) { + const float ray1x = x - x1; + const float ray1y = y - y1; + const float ray2x = x2 - x1; + const float ray2y = y2 - y1; + + const float dotProduct = ray1x * ray2x + ray1y * ray2y; + const float lineLengthSqr = squareFloat(ray2x) + squareFloat(ray2y); + const float projectionLengthSqr = dotProduct / lineLengthSqr; + + float projectionX; + float projectionY; + if (projectionLengthSqr < 0.0f) { + projectionX = x1; + projectionY = y1; + } else if (projectionLengthSqr > 1.0f) { + projectionX = x2; + projectionY = y2; + } else { + projectionX = x1 + projectionLengthSqr * ray2x; + projectionY = y1 + projectionLengthSqr * ray2y; + } + return getSquaredDistanceFloat(x, y, projectionX, projectionY); +} +} // namespace latinime +#endif // LATINIME_GEOMETRY_UTILS_H diff --git a/native/jni/src/gesture/gesture_decoder_wrapper.h b/native/jni/src/gesture/gesture_decoder_wrapper.h index 03c84b5fd..f8bfe7c79 100644 --- a/native/jni/src/gesture/gesture_decoder_wrapper.h +++ b/native/jni/src/gesture/gesture_decoder_wrapper.h @@ -37,37 +37,15 @@ class GestureDecoderWrapper : public IncrementalDecoderInterface { delete mIncrementalDecoderInterface; } - int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, - int *pointerIds, int *codes, int inputSize, int commitPoint, + int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, unsigned short *outWords, int *frequencies, int *outputIndices, int *outputTypes) { if (!mIncrementalDecoderInterface) { return 0; } return mIncrementalDecoderInterface->getSuggestions( - pInfo, inputXs, inputYs, times, pointerIds, codes, inputSize, commitPoint, - outWords, frequencies, outputIndices, outputTypes); - } - - void reset() { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->reset(); - } - - void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram, - const uint8_t *dictRoot, int rootPos) { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->setDict(dict, bigram, dictRoot, rootPos); - } - - void setPrevWord(const int32_t *prevWord, int prevWordLength) { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->setPrevWord(prevWord, prevWordLength); + pInfo, traverseSession, inputXs, inputYs, times, pointerIds, codes, + inputSize, commitPoint, outWords, frequencies, outputIndices, outputTypes); } static void setGestureDecoderFactoryMethod( @@ -76,7 +54,7 @@ class GestureDecoderWrapper : public IncrementalDecoderInterface { } private: - DISALLOW_COPY_AND_ASSIGN(GestureDecoderWrapper); + DISALLOW_IMPLICIT_CONSTRUCTORS(GestureDecoderWrapper); static IncrementalDecoderInterface *getGestureDecoderInstance(int maxWordLength, int maxWords) { if (sGestureDecoderFactoryMethod) { return sGestureDecoderFactoryMethod(maxWordLength, maxWords); diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/gesture/incremental_decoder_interface.h index 6d2e273da..04f0095e0 100644 --- a/native/jni/src/gesture/incremental_decoder_interface.h +++ b/native/jni/src/gesture/incremental_decoder_interface.h @@ -28,14 +28,14 @@ class ProximityInfo; class IncrementalDecoderInterface { public: - virtual int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, - int *pointerIds, int *codes, int inputSize, int commitPoint, - unsigned short *outWords, int *frequencies, int *outputIndices, int *outputTypes) = 0; - virtual void reset() = 0; - virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram, - const uint8_t *dictRoot, int rootPos) = 0; - virtual void setPrevWord(const int32_t *prevWord, int prevWordLength) = 0; + virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, + int *inputXs, int *inputYs, int *times, int *pointerIds, int *codes, + int inputSize, int commitPoint, unsigned short *outWords, int *frequencies, + int *outputIndices, int *outputTypes) = 0; + IncrementalDecoderInterface() { }; virtual ~IncrementalDecoderInterface() { }; + private: + DISALLOW_COPY_AND_ASSIGN(IncrementalDecoderInterface); }; } // namespace latinime #endif // LATINIME_INCREMENTAL_DECODER_INTERFACE_H diff --git a/native/jni/src/gesture/incremental_decoder_wrapper.h b/native/jni/src/gesture/incremental_decoder_wrapper.h index 698061548..5cb2ee368 100644 --- a/native/jni/src/gesture/incremental_decoder_wrapper.h +++ b/native/jni/src/gesture/incremental_decoder_wrapper.h @@ -37,37 +37,15 @@ class IncrementalDecoderWrapper : public IncrementalDecoderInterface { delete mIncrementalDecoderInterface; } - int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, - int *pointerIds, int *codes, int inputSize, int commitPoint, + int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, unsigned short *outWords, int *frequencies, int *outputIndices, int *outputTypes) { if (!mIncrementalDecoderInterface) { return 0; } return mIncrementalDecoderInterface->getSuggestions( - pInfo, inputXs, inputYs, times, pointerIds, codes, inputSize, commitPoint, - outWords, frequencies, outputIndices, outputTypes); - } - - void reset() { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->reset(); - } - - void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram, - const uint8_t *dictRoot, int rootPos) { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->setDict(dict, bigram, dictRoot, rootPos); - } - - void setPrevWord(const int32_t *prevWord, int prevWordLength) { - if (!mIncrementalDecoderInterface) { - return; - } - mIncrementalDecoderInterface->setPrevWord(prevWord, prevWordLength); + pInfo, traverseSession, inputXs, inputYs, times, pointerIds, codes, + inputSize, commitPoint, outWords, frequencies, outputIndices, outputTypes); } static void setIncrementalDecoderFactoryMethod( @@ -76,7 +54,7 @@ class IncrementalDecoderWrapper : public IncrementalDecoderInterface { } private: - DISALLOW_COPY_AND_ASSIGN(IncrementalDecoderWrapper); + DISALLOW_IMPLICIT_CONSTRUCTORS(IncrementalDecoderWrapper); static IncrementalDecoderInterface *getIncrementalDecoderInstance(int maxWordLength, int maxWords) { if (sIncrementalDecoderFactoryMethod) { diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp index cee408d46..1b9bac0f0 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -17,62 +17,76 @@ #include <cassert> #include <cmath> #include <cstring> -#include <string> #define LOG_TAG "LatinIME: proximity_info.cpp" #include "additional_proximity_chars.h" #include "char_utils.h" #include "defines.h" +#include "geometry_utils.h" +#include "jni.h" #include "proximity_info.h" namespace latinime { -inline void copyOrFillZero(void *to, const void *from, size_t size) { - if (from) { - memcpy(to, from, size); - } else { - memset(to, 0, size); +static inline void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray, jsize len, + jint *buffer) { + if (jArray && buffer) { + env->GetIntArrayRegion(jArray, 0, len, buffer); + } else if (buffer) { + memset(buffer, 0, len * sizeof(jint)); } } -ProximityInfo::ProximityInfo(const std::string localeStr, const int maxProximityCharsSize, +static inline void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray, jsize len, + jfloat *buffer) { + if (jArray && buffer) { + env->GetFloatArrayRegion(jArray, 0, len, buffer); + } else if (buffer) { + memset(buffer, 0, len * sizeof(jfloat)); + } +} + +ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int maxProximityCharsSize, const int keyboardWidth, const int keyboardHeight, const int gridWidth, - const int gridHeight, const int mostCommonKeyWidth, - const int32_t *proximityCharsArray, const int keyCount, const int32_t *keyXCoordinates, - const int32_t *keyYCoordinates, const int32_t *keyWidths, const int32_t *keyHeights, - const int32_t *keyCharCodes, const float *sweetSpotCenterXs, const float *sweetSpotCenterYs, - const float *sweetSpotRadii) + const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars, + const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates, + const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes, + const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs, + const jfloatArray sweetSpotRadii) : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), + MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth), MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth), CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight), KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs - && sweetSpotCenterYs && sweetSpotRadii), - mLocaleStr(localeStr) { + && sweetSpotCenterYs && sweetSpotRadii) { const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; if (DEBUG_PROXIMITY_INFO) { AKLOGI("Create proximity info array %d", proximityGridLength); } + const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr); + if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) { + AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length); + assert(false); + } + memset(mLocaleStr, 0, sizeof(mLocaleStr)); + env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr); mProximityCharsArray = new int32_t[proximityGridLength]; - memcpy(mProximityCharsArray, proximityCharsArray, - proximityGridLength * sizeof(mProximityCharsArray[0])); - - copyOrFillZero(mKeyXCoordinates, keyXCoordinates, KEY_COUNT * sizeof(mKeyXCoordinates[0])); - copyOrFillZero(mKeyYCoordinates, keyYCoordinates, KEY_COUNT * sizeof(mKeyYCoordinates[0])); - copyOrFillZero(mKeyWidths, keyWidths, KEY_COUNT * sizeof(mKeyWidths[0])); - copyOrFillZero(mKeyHeights, keyHeights, KEY_COUNT * sizeof(mKeyHeights[0])); - copyOrFillZero(mKeyCharCodes, keyCharCodes, KEY_COUNT * sizeof(mKeyCharCodes[0])); - copyOrFillZero(mSweetSpotCenterXs, sweetSpotCenterXs, - KEY_COUNT * sizeof(mSweetSpotCenterXs[0])); - copyOrFillZero(mSweetSpotCenterYs, sweetSpotCenterYs, - KEY_COUNT * sizeof(mSweetSpotCenterYs[0])); - copyOrFillZero(mSweetSpotRadii, sweetSpotRadii, KEY_COUNT * sizeof(mSweetSpotRadii[0])); - + safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityGridLength, mProximityCharsArray); + safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates); + safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates); + safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths); + safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights); + safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCharCodes); + safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs); + safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs); + safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii); initializeCodeToKeyIndex(); + initializeG(); } // Build the reversed look up table from the char code to the index in mKeyXCoordinates, @@ -121,6 +135,21 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { return false; } +static inline float getNormalizedSquaredDistanceFloat(float x1, float y1, float x2, float y2, + float scale) { + return squareFloat((x1 - x2) / scale) + squareFloat((y1 - y2) / scale); +} + +float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloat( + const int keyId, const int x, const int y) const { + const float centerX = static_cast<float>(getKeyCenterXOfIdG(keyId)); + const float centerY = static_cast<float>(getKeyCenterYOfIdG(keyId)); + const float touchX = static_cast<float>(x); + const float touchY = static_cast<float>(y); + const float keyWidth = static_cast<float>(getMostCommonKeyWidth()); + return getNormalizedSquaredDistanceFloat(centerX, centerY, touchX, touchY, keyWidth); +} + int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const { if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case const int left = mKeyXCoordinates[keyId]; @@ -160,7 +189,7 @@ void ProximityInfo::calculateNearbyKeyCodes( } } const int additionalProximitySize = - AdditionalProximityChars::getAdditionalCharsSize(&mLocaleStr, primaryKey); + AdditionalProximityChars::getAdditionalCharsSize(mLocaleStr, primaryKey); if (additionalProximitySize > 0) { inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { @@ -171,7 +200,7 @@ void ProximityInfo::calculateNearbyKeyCodes( } const int32_t *additionalProximityChars = - AdditionalProximityChars::getAdditionalChars(&mLocaleStr, primaryKey); + AdditionalProximityChars::getAdditionalChars(mLocaleStr, primaryKey); for (int j = 0; j < additionalProximitySize; ++j) { const int32_t ac = additionalProximityChars[j]; int k = 0; @@ -211,24 +240,65 @@ int ProximityInfo::getKeyIndex(const int c) const { return mCodeToKeyIndex[baseLowerC]; } -// TODO: [Staging] Optimize -void ProximityInfo::getCenters(int *centerXs, int *centerYs, int *codeToKeyIndex, - int *keyToCodeIndex, int *keyCount, int *keyWidth) const { - *keyCount = KEY_COUNT; - *keyWidth = sqrt(static_cast<float>(MOST_COMMON_KEY_WIDTH_SQUARE)); +int ProximityInfo::getKeyCode(const int keyIndex) const { + if (keyIndex < 0 || keyIndex >= KEY_COUNT) { + return NOT_AN_INDEX; + } + return mKeyToCodeIndexG[keyIndex]; +} +void ProximityInfo::initializeG() { + // TODO: Optimize for (int i = 0; i < KEY_COUNT; ++i) { const int code = mKeyCharCodes[i]; const int lowerCode = toBaseLowerCase(code); - centerXs[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2; - centerYs[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2; - codeToKeyIndex[code] = i; + mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2; + mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2; if (code != lowerCode && lowerCode >= 0 && lowerCode <= MAX_CHAR_CODE) { - codeToKeyIndex[lowerCode] = i; - keyToCodeIndex[i] = lowerCode; + mCodeToKeyIndex[lowerCode] = i; + mKeyToCodeIndexG[i] = lowerCode; } else { - keyToCodeIndex[i] = code; + mKeyToCodeIndexG[i] = code; + } + } + for (int i = 0; i < KEY_COUNT; i++) { + mKeyKeyDistancesG[i][i] = 0; + for (int j = i + 1; j < KEY_COUNT; j++) { + mKeyKeyDistancesG[i][j] = getDistanceInt( + mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]); + mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j]; } } } + +float ProximityInfo::getKeyCenterXOfCharG(int charCode) const { + return getKeyCenterXOfIdG(getKeyIndex(charCode)); +} + +float ProximityInfo::getKeyCenterYOfCharG(int charCode) const { + return getKeyCenterYOfIdG(getKeyIndex(charCode)); +} + +float ProximityInfo::getKeyCenterXOfIdG(int keyId) const { + if (keyId >= 0) { + return mCenterXsG[keyId]; + } + return 0; +} + +float ProximityInfo::getKeyCenterYOfIdG(int keyId) const { + if (keyId >= 0) { + return mCenterYsG[keyId]; + } + return 0; +} + +int ProximityInfo::getKeyKeyDistanceG(int key0, int key1) const { + const int keyId0 = getKeyIndex(key0); + const int keyId1 = getKeyIndex(key1); + if (keyId0 >= 0 && keyId1 >= 0) { + return mKeyKeyDistancesG[keyId0][keyId1]; + } + return 0; +} } // namespace latinime diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index abd07dd3e..8a407e71a 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -18,9 +18,9 @@ #define LATINIME_PROXIMITY_INFO_H #include <stdint.h> -#include <string> #include "defines.h" +#include "jni.h" namespace latinime { @@ -28,16 +28,18 @@ class Correction; class ProximityInfo { public: - ProximityInfo(const std::string localeStr, const int maxProximityCharsSize, + ProximityInfo(JNIEnv *env, const jstring localeJStr, const int maxProximityCharsSize, const int keyboardWidth, const int keyboardHeight, const int gridWidth, - const int gridHeight, const int mostCommonkeyWidth, - const int32_t *proximityCharsArray, const int keyCount, const int32_t *keyXCoordinates, - const int32_t *keyYCoordinates, const int32_t *keyWidths, const int32_t *keyHeights, - const int32_t *keyCharCodes, const float *sweetSpotCenterXs, - const float *sweetSpotCenterYs, const float *sweetSpotRadii); + const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars, + const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates, + const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes, + const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs, + const jfloatArray sweetSpotRadii); ~ProximityInfo(); bool hasSpaceProximity(const int x, const int y) const; int getNormalizedSquaredDistance(const int inputIndex, const int proximityIndex) const; + float getNormalizedSquaredDistanceFromCenterFloat( + const int keyId, const int x, const int y) const; bool sameAsTyped(const unsigned short *word, int length) const; int squaredDistanceToEdge(const int keyId, const int x, const int y) const; bool isOnKey(const int keyId, const int x, const int y) const { @@ -49,6 +51,7 @@ class ProximityInfo { return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom; } int getKeyIndex(const int c) const; + int getKeyCode(const int keyIndex) const; bool hasSweetSpotData(const int keyIndex) const { // When there are no calibration data for a key, // the radius of the key is assigned to zero. @@ -70,11 +73,15 @@ class ProximityInfo { return HAS_TOUCH_POSITION_CORRECTION_DATA; } + int getMostCommonKeyWidth() const { + return MOST_COMMON_KEY_WIDTH; + } + int getMostCommonKeyWidthSquare() const { return MOST_COMMON_KEY_WIDTH_SQUARE; } - std::string getLocaleStr() const { + const char *getLocaleStr() const { return mLocaleStr; } @@ -98,6 +105,12 @@ class ProximityInfo { return GRID_HEIGHT; } + float getKeyCenterXOfCharG(int charCode) const; + float getKeyCenterYOfCharG(int charCode) const; + float getKeyCenterXOfIdG(int keyId) const; + float getKeyCenterYOfIdG(int keyId) const; + int getKeyKeyDistanceG(int key0, int key1) const; + // Returns the keyboard key-center information. void getCenters(int *centersX, int *centersY, int *codeToKeyIndex, int *keyToCodeIndex, int *keyCount, int *keyWidth) const; @@ -113,6 +126,7 @@ class ProximityInfo { int getStartIndexFromCoordinates(const int x, const int y) const; void initializeCodeToKeyIndex(); + void initializeG(); float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const; float calculateSquaredDistanceFromSweetSpotCenter( const int keyIndex, const int inputIndex) const; @@ -123,12 +137,13 @@ class ProximityInfo { const int KEYBOARD_HEIGHT; const int GRID_WIDTH; const int GRID_HEIGHT; + const int MOST_COMMON_KEY_WIDTH; const int MOST_COMMON_KEY_WIDTH_SQUARE; const int CELL_WIDTH; const int CELL_HEIGHT; const int KEY_COUNT; const bool HAS_TOUCH_POSITION_CORRECTION_DATA; - const std::string mLocaleStr; + char mLocaleStr[MAX_LOCALE_STRING_LENGTH]; int32_t *mProximityCharsArray; int32_t mKeyXCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD]; int32_t mKeyYCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD]; @@ -139,6 +154,11 @@ class ProximityInfo { float mSweetSpotCenterYs[MAX_KEY_COUNT_IN_A_KEYBOARD]; float mSweetSpotRadii[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mCodeToKeyIndex[MAX_CHAR_CODE + 1]; + + int mKeyToCodeIndexG[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int mCenterXsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int mCenterYsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int mKeyKeyDistancesG[MAX_KEY_COUNT_IN_A_KEYBOARD][MAX_KEY_COUNT_IN_A_KEYBOARD]; // TODO: move to correction.h }; } // namespace latinime diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index 76d45516e..474c40757 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -160,6 +160,21 @@ class ProximityInfoState { return mTouchPositionCorrectionEnabled; } + inline bool sameAsTyped(const unsigned short *word, int length) const { + if (length != mInputLength) { + return false; + } + const int *inputCodes = mInputCodes; + while (length--) { + if (static_cast<unsigned int>(*inputCodes) != static_cast<unsigned int>(*word)) { + return false; + } + inputCodes += MAX_PROXIMITY_CHARS_SIZE_INTERNAL; + word++; + } + return true; + } + private: DISALLOW_COPY_AND_ASSIGN(ProximityInfoState); ///////////////////////////////////////// @@ -179,21 +194,6 @@ class ProximityInfoState { return mInputXCoordinates && mInputYCoordinates; } - bool sameAsTyped(const unsigned short *word, int length) const { - if (length != mInputLength) { - return false; - } - const int *inputCodes = mInputCodes; - while (length--) { - if ((unsigned int) *inputCodes != (unsigned int) *word) { - return false; - } - inputCodes += MAX_PROXIMITY_CHARS_SIZE_INTERNAL; - word++; - } - return true; - } - // const const ProximityInfo *mProximityInfo; bool mHasTouchPositionCorrectionData; diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h index d63364514..1ae9c7cbb 100644 --- a/native/jni/src/terminal_attributes.h +++ b/native/jni/src/terminal_attributes.h @@ -46,7 +46,7 @@ class TerminalAttributes { // Gets the shortcut target itself as a uint16_t string. For parameters and return value // see BinaryFormat::getWordAtAddress. // TODO: make the output an uint32_t* to handle the whole unicode range. - inline int getNextShortcutTarget(const int maxDepth, uint16_t *outWord) { + inline int getNextShortcutTarget(const int maxDepth, uint16_t *outWord, int *outFreq) { const int shortcutFlags = BinaryFormat::getFlagsAndForwardPointer(mDict, &mPos); mHasNextShortcutTarget = 0 != (shortcutFlags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT); @@ -56,6 +56,7 @@ class TerminalAttributes { if (NOT_A_CHARACTER == charCode) break; outWord[i] = (uint16_t)charCode; } + *outFreq = BinaryFormat::getAttributeFrequencyFromFlags(shortcutFlags); mPos += BinaryFormat::CHARACTER_ARRAY_TERMINATOR_SIZE; return i; } diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index b6b0210cc..cc6d39a29 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -63,8 +63,8 @@ static inline unsigned int getCodesBufferSize(const int *codes, const int codesS // TODO: This needs to take a const unsigned short* and not tinker with its contents static inline void addWord( - unsigned short *word, int length, int frequency, WordsPriorityQueue *queue) { - queue->push(frequency, word, length); + unsigned short *word, int length, int frequency, WordsPriorityQueue *queue, int type) { + queue->push(frequency, word, length, type); } // Return the replacement code point for a digraph, or 0 if none. @@ -213,8 +213,8 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, AKLOGI("Max normalized score = %f", ns); } const int suggestedWordsCount = - queuePool.getMasterQueue()->outputSuggestions( - masterCorrection.getPrimaryInputWord(), codesSize, frequencies, outWords); + queuePool.getMasterQueue()->outputSuggestions(masterCorrection.getPrimaryInputWord(), + codesSize, frequencies, outWords, outputTypes); if (DEBUG_DICT) { float ns = queuePool.getMasterQueue()->getHighestNormalizedScore( @@ -391,7 +391,12 @@ inline void UnigramDictionary::onTerminal(const int probability, const int finalProbability = correction->getFinalProbability(probability, &wordPointer, &wordLength); if (finalProbability != NOT_A_PROBABILITY) { - addWord(wordPointer, wordLength, finalProbability, masterQueue); + if (0 != finalProbability) { + // If the probability is 0, we don't want to add this word. However we still + // want to add its shortcuts (including a possible whitelist entry) if any. + addWord(wordPointer, wordLength, finalProbability, masterQueue, + Dictionary::KIND_CORRECTION); + } const int shortcutProbability = finalProbability > 0 ? finalProbability - 1 : 0; // Please note that the shortcut candidates will be added to the master queue only. @@ -406,10 +411,21 @@ inline void UnigramDictionary::onTerminal(const int probability, // with the same score. For the moment we use -1 to make sure the shortcut will // never be in front of the word. uint16_t shortcutTarget[MAX_WORD_LENGTH_INTERNAL]; + int shortcutFrequency; const int shortcutTargetStringLength = iterator.getNextShortcutTarget( - MAX_WORD_LENGTH_INTERNAL, shortcutTarget); - addWord(shortcutTarget, shortcutTargetStringLength, shortcutProbability, - masterQueue); + MAX_WORD_LENGTH_INTERNAL, shortcutTarget, &shortcutFrequency); + int shortcutScore; + int kind; + if (shortcutFrequency == BinaryFormat::WHITELIST_SHORTCUT_FREQUENCY + && correction->sameAsTyped()) { + shortcutScore = S_INT_MAX; + kind = Dictionary::KIND_WHITELIST; + } else { + shortcutScore = shortcutProbability; + kind = Dictionary::KIND_CORRECTION; + } + addWord(shortcutTarget, shortcutTargetStringLength, shortcutScore, + masterQueue, kind); } } } @@ -424,7 +440,7 @@ inline void UnigramDictionary::onTerminal(const int probability, } const int finalProbability = correction->getFinalProbabilityForSubQueue( probability, &wordPointer, &wordLength, inputIndex); - addWord(wordPointer, wordLength, finalProbability, subQueue); + addWord(wordPointer, wordLength, finalProbability, subQueue, Dictionary::KIND_CORRECTION); } } @@ -572,7 +588,8 @@ int UnigramDictionary::getSubStringSuggestion( AKLOGI("Split two words: freq = %d, length = %d, %d, isSpace ? %d", pairFreq, inputLength, tempOutputWordLength, isSpaceProximity); } - addWord(outputWord, tempOutputWordLength, pairFreq, queuePool->getMasterQueue()); + addWord(outputWord, tempOutputWordLength, pairFreq, queuePool->getMasterQueue(), + Dictionary::KIND_CORRECTION); } return FLAG_MULTIPLE_SUGGEST_CONTINUE; } diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h index c0dedb59d..1e4e00a23 100644 --- a/native/jni/src/words_priority_queue.h +++ b/native/jni/src/words_priority_queue.h @@ -33,12 +33,14 @@ class WordsPriorityQueue { unsigned short mWord[MAX_WORD_LENGTH_INTERNAL]; int mWordLength; bool mUsed; + int mType; - void setParams(int score, unsigned short *word, int wordLength) { + void setParams(int score, unsigned short *word, int wordLength, int type) { mScore = score; mWordLength = wordLength; memcpy(mWord, word, sizeof(unsigned short) * wordLength); mUsed = true; + mType = type; } }; @@ -56,7 +58,7 @@ class WordsPriorityQueue { delete[] mSuggestedWords; } - void push(int score, unsigned short *word, int wordLength) { + void push(int score, unsigned short *word, int wordLength, int type) { SuggestedWord *sw = 0; if (mSuggestions.size() >= MAX_WORDS) { sw = mSuggestions.top(); @@ -69,9 +71,9 @@ class WordsPriorityQueue { } } if (sw == 0) { - sw = getFreeSuggestedWord(score, word, wordLength); + sw = getFreeSuggestedWord(score, word, wordLength, type); } else { - sw->setParams(score, word, wordLength); + sw->setParams(score, word, wordLength, type); } if (sw == 0) { AKLOGE("SuggestedWord is accidentally null."); @@ -94,7 +96,7 @@ class WordsPriorityQueue { } int outputSuggestions(const unsigned short *before, const int beforeLength, - int *frequencies, unsigned short *outputChars) { + int *frequencies, unsigned short *outputChars, int* outputTypes) { mHighestSuggestedWord = 0; const unsigned int size = min( MAX_WORDS, static_cast<unsigned int>(mSuggestions.size())); @@ -127,7 +129,7 @@ class WordsPriorityQueue { } } if (maxIndex > 0 && nsMaxSw) { - memmove(&swBuffer[1], &swBuffer[0], maxIndex * sizeof(SuggestedWord*)); + memmove(&swBuffer[1], &swBuffer[0], maxIndex * sizeof(SuggestedWord *)); swBuffer[0] = nsMaxSw; } } @@ -138,11 +140,12 @@ class WordsPriorityQueue { continue; } const unsigned int wordLength = sw->mWordLength; - char *targetAdr = (char*) outputChars + i * MAX_WORD_LENGTH * sizeof(short); + unsigned short *targetAddress = outputChars + i * MAX_WORD_LENGTH; frequencies[i] = sw->mScore; - memcpy(targetAdr, sw->mWord, (wordLength) * sizeof(short)); + outputTypes[i] = sw->mType; + memcpy(targetAddress, sw->mWord, wordLength * sizeof(unsigned short)); if (wordLength < MAX_WORD_LENGTH) { - ((unsigned short*) targetAdr)[wordLength] = 0; + targetAddress[wordLength] = 0; } sw->mUsed = false; } @@ -191,10 +194,10 @@ class WordsPriorityQueue { }; SuggestedWord *getFreeSuggestedWord(int score, unsigned short *word, - int wordLength) { + int wordLength, int type) { for (unsigned int i = 0; i < MAX_WORD_LENGTH; ++i) { if (!mSuggestedWords[i].mUsed) { - mSuggestedWords[i].setParams(score, word, wordLength); + mSuggestedWords[i].setParams(score, word, wordLength, type); return &mSuggestedWords[i]; } } @@ -219,7 +222,7 @@ class WordsPriorityQueue { before, beforeLength, word, wordLength, score); } - typedef std::priority_queue<SuggestedWord*, std::vector<SuggestedWord*>, + typedef std::priority_queue<SuggestedWord *, std::vector<SuggestedWord *>, wordComparator> Suggestions; Suggestions mSuggestions; const unsigned int MAX_WORDS; |