diff options
Diffstat (limited to 'native/jni')
27 files changed, 517 insertions, 301 deletions
diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 1b7301b19..1725a7638 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -37,7 +37,6 @@ LATIN_IME_JNI_SRC_FILES := \ com_android_inputmethod_keyboard_ProximityInfo.cpp \ com_android_inputmethod_latin_BinaryDictionary.cpp \ com_android_inputmethod_latin_DicTraverseSession.cpp \ - com_android_inputmethod_latin_NativeUtils.cpp \ jni_common.cpp LATIN_IME_CORE_SRC_FILES := \ @@ -47,6 +46,7 @@ LATIN_IME_CORE_SRC_FILES := \ char_utils.cpp \ correction.cpp \ dictionary.cpp \ + dic_traverse_wrapper.cpp \ proximity_info.cpp \ proximity_info_state.cpp \ unigram_dictionary.cpp \ diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp index f9b23f06d..545d91a70 100644 --- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp +++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp @@ -43,8 +43,8 @@ static void latinime_Keyboard_release(JNIEnv *env, jobject object, jlong proximi static JNINativeMethod sKeyboardMethods[] = { {"setProximityInfoNative", "(Ljava/lang/String;IIIIII[II[I[I[I[I[I[F[F[F)J", - (void*)latinime_Keyboard_setProximityInfo}, - {"releaseProximityInfoNative", "(J)V", (void*)latinime_Keyboard_release} + reinterpret_cast<void *>(latinime_Keyboard_setProximityInfo)}, + {"releaseProximityInfoNative", "(J)V", reinterpret_cast<void *>(latinime_Keyboard_release)} }; int register_ProximityInfo(JNIEnv *env) { diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 6e2efbec1..5a287a122 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -14,15 +14,12 @@ * limitations under the License. */ + +#include <cstring> // for memset() + #define LOG_TAG "LatinIME: jni: BinaryDictionary" -#include "binary_format.h" -#include "com_android_inputmethod_latin_BinaryDictionary.h" -#include "correction.h" -#include "defines.h" -#include "dictionary.h" -#include "jni.h" -#include "jni_common.h" +#include "defines.h" // for macros below #ifdef USE_MMAP_FOR_DICTIONARY #include <cerrno> @@ -32,6 +29,13 @@ #include <cstdlib> #endif // USE_MMAP_FOR_DICTIONARY +#include "binary_format.h" +#include "com_android_inputmethod_latin_BinaryDictionary.h" +#include "correction.h" +#include "dictionary.h" +#include "jni.h" +#include "jni_common.h" + namespace latinime { class ProximityInfo; @@ -71,7 +75,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); return 0; } - dictBuf = (void *)((char *)dictBuf + adjust); + dictBuf = reinterpret_cast<void *>(reinterpret_cast<char *>(dictBuf) + adjust); #else // USE_MMAP_FOR_DICTIONARY /* malloc version */ FILE *file = 0; @@ -106,10 +110,11 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, return 0; } Dictionary *dictionary = 0; - if (BinaryFormat::UNKNOWN_FORMAT == BinaryFormat::detectFormat((uint8_t*)dictBuf)) { + if (BinaryFormat::UNKNOWN_FORMAT + == BinaryFormat::detectFormat(reinterpret_cast<uint8_t *>(dictBuf))) { AKLOGE("DICT: dictionary format is unknown, bad magic number"); #ifdef USE_MMAP_FOR_DICTIONARY - releaseDictBuf(((char*)dictBuf) - adjust, adjDictSize, fd); + releaseDictBuf(reinterpret_cast<char *>(dictBuf) - adjust, adjDictSize, fd); #else // USE_MMAP_FOR_DICTIONARY releaseDictBuf(dictBuf, 0, 0); #endif // USE_MMAP_FOR_DICTIONARY @@ -124,106 +129,132 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray, - jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdArray, - jintArray inputArray, jint arraySize, jint commitPoint, jboolean isGesture, - jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, - jintArray frequencyArray, jintArray spaceIndexArray, jintArray outputTypesArray) { + jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray, + jintArray inputCodePointsArray, jint arraySize, jint commitPoint, jboolean isGesture, + jintArray prevWordCodePointsForBigrams, jboolean useFullEditDistance, + jcharArray outputCharsArray, jintArray scoresArray, jintArray spaceIndicesArray, + jintArray outputTypesArray) { Dictionary *dictionary = reinterpret_cast<Dictionary*>(dict); if (!dictionary) return 0; ProximityInfo *pInfo = reinterpret_cast<ProximityInfo*>(proximityInfo); void *traverseSession = reinterpret_cast<void*>(dicTraverseSession); - int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, 0); - int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, 0); - int *times = env->GetIntArrayElements(timesArray, 0); - int *pointerIds = env->GetIntArrayElements(pointerIdArray, 0); - int *frequencies = env->GetIntArrayElements(frequencyArray, 0); - int *inputCodes = env->GetIntArrayElements(inputArray, 0); - jchar *outputChars = env->GetCharArrayElements(outputArray, 0); - int *spaceIndices = env->GetIntArrayElements(spaceIndexArray, 0); - int *outputTypes = env->GetIntArrayElements(outputTypesArray, 0); - jint *prevWordChars = prevWordForBigrams - ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; - jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; + + // Input values + int xCoordinates[arraySize]; + int yCoordinates[arraySize]; + int times[arraySize]; + int pointerIds[arraySize]; + const jsize inputCodePointsLength = env->GetArrayLength(inputCodePointsArray); + int inputCodePoints[inputCodePointsLength]; + const jsize prevWordCodePointsLength = + prevWordCodePointsForBigrams ? env->GetArrayLength(prevWordCodePointsForBigrams) : 0; + int prevWordCodePointsInternal[prevWordCodePointsLength]; + int *prevWordCodePoints = 0; + env->GetIntArrayRegion(xCoordinatesArray, 0, arraySize, xCoordinates); + env->GetIntArrayRegion(yCoordinatesArray, 0, arraySize, yCoordinates); + env->GetIntArrayRegion(timesArray, 0, arraySize, times); + env->GetIntArrayRegion(pointerIdsArray, 0, arraySize, pointerIds); + env->GetIntArrayRegion(inputCodePointsArray, 0, inputCodePointsLength, inputCodePoints); + if (prevWordCodePointsForBigrams) { + env->GetIntArrayRegion(prevWordCodePointsForBigrams, 0, prevWordCodePointsLength, + prevWordCodePointsInternal); + prevWordCodePoints = prevWordCodePointsInternal; + } + + // Output values + // TODO: Should be "outputCodePointsLength" and "int outputCodePoints[]" + const jsize outputCharsLength = env->GetArrayLength(outputCharsArray); + unsigned short outputChars[outputCharsLength]; + const jsize scoresLength = env->GetArrayLength(scoresArray); + int scores[scoresLength]; + const jsize spaceIndicesLength = env->GetArrayLength(spaceIndicesArray); + int spaceIndices[spaceIndicesLength]; + const jsize outputTypesLength = env->GetArrayLength(outputTypesArray); + int outputTypes[outputTypesLength]; + memset(outputChars, 0, outputCharsLength * sizeof(outputChars[0])); + memset(scores, 0, scoresLength * sizeof(scores[0])); + memset(spaceIndices, 0, spaceIndicesLength * sizeof(spaceIndices[0])); + memset(outputTypes, 0, outputTypesLength * sizeof(outputTypes[0])); int count; if (isGesture || arraySize > 1) { count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates, - times, pointerIds, inputCodes, arraySize, prevWordChars, prevWordLength, - commitPoint, isGesture, useFullEditDistance, (unsigned short*) outputChars, - frequencies, spaceIndices, outputTypes); + times, pointerIds, inputCodePoints, arraySize, prevWordCodePoints, + prevWordCodePointsLength, commitPoint, isGesture, useFullEditDistance, outputChars, + scores, spaceIndices, outputTypes); } else { - count = dictionary->getBigrams(prevWordChars, prevWordLength, inputCodes, - arraySize, (unsigned short*) outputChars, frequencies, outputTypes); + count = dictionary->getBigrams(prevWordCodePoints, prevWordCodePointsLength, + inputCodePoints, arraySize, outputChars, scores, outputTypes); } - if (prevWordChars) { - env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); - } - env->ReleaseIntArrayElements(outputTypesArray, outputTypes, 0); - env->ReleaseIntArrayElements(spaceIndexArray, spaceIndices, 0); - env->ReleaseCharArrayElements(outputArray, outputChars, 0); - env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); - env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); - env->ReleaseIntArrayElements(pointerIdArray, pointerIds, 0); - env->ReleaseIntArrayElements(timesArray, times, 0); - env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0); - env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0); + // Copy back the output values + // TODO: Should be SetIntArrayRegion() + env->SetCharArrayRegion(outputCharsArray, 0, outputCharsLength, outputChars); + env->SetIntArrayRegion(scoresArray, 0, scoresLength, scores); + env->SetIntArrayRegion(spaceIndicesArray, 0, spaceIndicesLength, spaceIndices); + env->SetIntArrayRegion(outputTypesArray, 0, outputTypesLength, outputTypes); + return count; } static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jobject object, jlong dict, - jintArray wordArray, jint wordLength) { - Dictionary *dictionary = (Dictionary*)dict; - if (!dictionary) return (jboolean) false; - jint *word = env->GetIntArrayElements(wordArray, 0); - jint result = dictionary->getFrequency(word, wordLength); - env->ReleaseIntArrayElements(wordArray, word, JNI_ABORT); - return result; + jintArray wordArray) { + Dictionary *dictionary = reinterpret_cast<Dictionary*>(dict); + if (!dictionary) return 0; + const jsize codePointLength = env->GetArrayLength(wordArray); + int codePoints[codePointLength]; + env->GetIntArrayRegion(wordArray, 0, codePointLength, codePoints); + return dictionary->getFrequency(codePoints, codePointLength); } static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject object, jlong dict, jintArray wordArray1, jintArray wordArray2) { - Dictionary *dictionary = (Dictionary*)dict; + Dictionary *dictionary = reinterpret_cast<Dictionary*>(dict); if (!dictionary) return (jboolean) false; - jint *word1 = env->GetIntArrayElements(wordArray1, 0); - jint *word2 = env->GetIntArrayElements(wordArray2, 0); - jsize length1 = word1 ? env->GetArrayLength(wordArray1) : 0; - jsize length2 = word2 ? env->GetArrayLength(wordArray2) : 0; - jboolean result = dictionary->isValidBigram(word1, length1, word2, length2); - env->ReleaseIntArrayElements(wordArray2, word2, JNI_ABORT); - env->ReleaseIntArrayElements(wordArray1, word1, JNI_ABORT); - return result; + const jsize codePointLength1 = env->GetArrayLength(wordArray1); + const jsize codePointLength2 = env->GetArrayLength(wordArray2); + int codePoints1[codePointLength1]; + int codePoints2[codePointLength2]; + env->GetIntArrayRegion(wordArray1, 0, codePointLength1, codePoints1); + env->GetIntArrayRegion(wordArray2, 0, codePointLength2, codePoints2); + return dictionary->isValidBigram(codePoints1, codePointLength1, codePoints2, codePointLength2); } static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object, - jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) { - jchar *beforeChars = env->GetCharArrayElements(before, 0); - jchar *afterChars = env->GetCharArrayElements(after, 0); - jfloat result = Correction::RankingAlgorithm::calcNormalizedScore((unsigned short*)beforeChars, - beforeLength, (unsigned short*)afterChars, afterLength, score); - env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); - env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); - return result; + jcharArray before, jcharArray after, jint score) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + jchar beforeChars[beforeLength]; + jchar afterChars[afterLength]; + env->GetCharArrayRegion(before, 0, beforeLength, beforeChars); + env->GetCharArrayRegion(after, 0, afterLength, afterChars); + return Correction::RankingAlgorithm::calcNormalizedScore( + reinterpret_cast<unsigned short *>(beforeChars), beforeLength, + reinterpret_cast<unsigned short *>(afterChars), afterLength, score); } static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jobject object, - jcharArray before, jint beforeLength, jcharArray after, jint afterLength) { - jchar *beforeChars = env->GetCharArrayElements(before, 0); - jchar *afterChars = env->GetCharArrayElements(after, 0); - jint result = Correction::RankingAlgorithm::editDistance( - (unsigned short*)beforeChars, beforeLength, (unsigned short*)afterChars, afterLength); - env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); - env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); - return result; + jcharArray before, jcharArray after) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + jchar beforeChars[beforeLength]; + jchar afterChars[afterLength]; + env->GetCharArrayRegion(before, 0, beforeLength, beforeChars); + env->GetCharArrayRegion(after, 0, afterLength, afterChars); + return Correction::RankingAlgorithm::editDistance( + reinterpret_cast<unsigned short *>(beforeChars), beforeLength, + reinterpret_cast<unsigned short *>(afterChars), afterLength); } static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jlong dict) { - Dictionary *dictionary = (Dictionary*)dict; + Dictionary *dictionary = reinterpret_cast<Dictionary*>(dict); if (!dictionary) return; void *dictBuf = dictionary->getDict(); if (!dictBuf) return; #ifdef USE_MMAP_FOR_DICTIONARY - releaseDictBuf((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), + releaseDictBuf( + reinterpret_cast<void *>( + reinterpret_cast<char *>(dictBuf) - dictionary->getDictBufAdjust()), dictionary->getDictSize() + dictionary->getDictBufAdjust(), dictionary->getMmapFd()); #else // USE_MMAP_FOR_DICTIONARY releaseDictBuf(dictBuf, 0, 0); @@ -247,15 +278,19 @@ static void releaseDictBuf(void *dictBuf, const size_t length, int fd) { } static JNINativeMethod sMethods[] = { - {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, - {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, + {"openNative", "(Ljava/lang/String;JJIIIII)J", + reinterpret_cast<void *>(latinime_BinaryDictionary_open)}, + {"closeNative", "(J)V", reinterpret_cast<void *>(latinime_BinaryDictionary_close)}, {"getSuggestionsNative", "(JJJ[I[I[I[I[IIIZ[IZ[C[I[I[I)I", - (void*) latinime_BinaryDictionary_getSuggestions}, - {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, - {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, - {"calcNormalizedScoreNative", "([CI[CII)F", - (void*)latinime_BinaryDictionary_calcNormalizedScore}, - {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} + reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)}, + {"getFrequencyNative", "(J[I)I", + reinterpret_cast<void *>(latinime_BinaryDictionary_getFrequency)}, + {"isValidBigramNative", "(J[I[I)Z", + reinterpret_cast<void *>(latinime_BinaryDictionary_isValidBigram)}, + {"calcNormalizedScoreNative", "([C[CI)F", + reinterpret_cast<void *>(latinime_BinaryDictionary_calcNormalizedScore)}, + {"editDistanceNative", "([C[C)I", + reinterpret_cast<void *>(latinime_BinaryDictionary_editDistance)} }; int register_BinaryDictionary(JNIEnv *env) { diff --git a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp index 0f5c39642..947360e8e 100644 --- a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp +++ b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp @@ -17,37 +17,42 @@ #define LOG_TAG "LatinIME: jni: Session" #include "com_android_inputmethod_latin_DicTraverseSession.h" +#include "dic_traverse_wrapper.h" #include "jni.h" #include "jni_common.h" namespace latinime { -void *(*DicTraverseWrapper::sDicTraverseSessionFactoryMethod)() = 0; -void (*DicTraverseWrapper::sDicTraverseSessionReleaseMethod)(void *) = 0; -void (*DicTraverseWrapper::sDicTraverseSessionInitMethod)( - JNIEnv *, void *, const jintArray, const jint) = 0; - -static jlong latinime_setDicTraverseSession(JNIEnv *env, jobject object, - jstring localejStr) { - void *traverseSession = DicTraverseWrapper::getDicTraverseSession(); +class Dictionary; +static jlong latinime_setDicTraverseSession(JNIEnv *env, jobject object, jstring localeJStr) { + void *traverseSession = DicTraverseWrapper::getDicTraverseSession(env, localeJStr); return reinterpret_cast<jlong>(traverseSession); } -static void latinime_initDicTraverseSession(JNIEnv *env, jlong traverseSession, - jintArray previousWord, jint previousWordLength) { +static void latinime_initDicTraverseSession(JNIEnv *env, jobject object, jlong traverseSession, + jlong dictionary, jintArray previousWord, jint previousWordLength) { void *ts = reinterpret_cast<void*>(traverseSession); - DicTraverseWrapper::initDicTraverseSession(env, ts, previousWord, previousWordLength); + Dictionary *dict = reinterpret_cast<Dictionary*>(dictionary); + if (!previousWord) { + DicTraverseWrapper::initDicTraverseSession(ts, dict, 0, 0); + return; + } + int prevWord[previousWordLength]; + env->GetIntArrayRegion(previousWord, 0, previousWordLength, prevWord); + DicTraverseWrapper::initDicTraverseSession(ts, dict, prevWord, previousWordLength); } -static void latinime_DicTraverseSession_release( - JNIEnv *env, jobject object, jlong traverseSession) { +static void latinime_releaseDicTraverseSession(JNIEnv *env, jobject object, jlong traverseSession) { void *ts = reinterpret_cast<void*>(traverseSession); DicTraverseWrapper::releaseDicTraverseSession(ts); } static JNINativeMethod sMethods[] = { - {"setDicTraverseSessionNative", "(Ljava/lang/String;)J", (void*)latinime_setDicTraverseSession}, - {"initDicTraverseSessionNative", "(J[II)V", (void*)latinime_initDicTraverseSession}, - {"releaseDicTraverseSessionNative", "(J)V", (void*)latinime_DicTraverseSession_release} + {"setDicTraverseSessionNative", "(Ljava/lang/String;)J", + reinterpret_cast<void *>(latinime_setDicTraverseSession)}, + {"initDicTraverseSessionNative", "(JJ[II)V", + reinterpret_cast<void *>(latinime_initDicTraverseSession)}, + {"releaseDicTraverseSessionNative", "(J)V", + reinterpret_cast<void *>(latinime_releaseDicTraverseSession)} }; int register_DicTraverseSession(JNIEnv *env) { diff --git a/native/jni/com_android_inputmethod_latin_DicTraverseSession.h b/native/jni/com_android_inputmethod_latin_DicTraverseSession.h index a76815d7f..37531e96b 100644 --- a/native/jni/com_android_inputmethod_latin_DicTraverseSession.h +++ b/native/jni/com_android_inputmethod_latin_DicTraverseSession.h @@ -21,33 +21,6 @@ #include "jni.h" namespace latinime { - -// TODO: Remove -class DicTraverseWrapper { - public: - static void *getDicTraverseSession() { - if (sDicTraverseSessionFactoryMethod) { - return sDicTraverseSessionFactoryMethod(); - } - return 0; - } - static void initDicTraverseSession(JNIEnv *env, void *traverseSession, - const jintArray prevWord, const jint prevWordLength) { - if (sDicTraverseSessionInitMethod) { - sDicTraverseSessionInitMethod(env, traverseSession, prevWord, prevWordLength); - } - } - static void releaseDicTraverseSession(void *traverseSession) { - if (sDicTraverseSessionReleaseMethod) { - sDicTraverseSessionReleaseMethod(traverseSession); - } - } - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseWrapper); - static void *(*sDicTraverseSessionFactoryMethod)(); - static void (*sDicTraverseSessionInitMethod)(JNIEnv *, void *, const jintArray, const jint); - static void (*sDicTraverseSessionReleaseMethod)(void *); -}; int register_DicTraverseSession(JNIEnv *env); } // namespace latinime #endif // _COM_ANDROID_INPUTMETHOD_LATIN_DICTRAVERSESESSION_H diff --git a/native/jni/com_android_inputmethod_latin_NativeUtils.cpp b/native/jni/com_android_inputmethod_latin_NativeUtils.cpp deleted file mode 100644 index 8f1afbeb6..000000000 --- a/native/jni/com_android_inputmethod_latin_NativeUtils.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. - */ - -#include "com_android_inputmethod_latin_NativeUtils.h" -#include "jni.h" -#include "jni_common.h" - -#include <cmath> - -namespace latinime { - -static float latinime_NativeUtils_powf(float x, float y) { - return powf(x, y); -} - -static JNINativeMethod sMethods[] = { - {"powf", "(FF)F", (void*)latinime_NativeUtils_powf} -}; - -int register_NativeUtils(JNIEnv *env) { - const char *const kClassPathName = "com/android/inputmethod/latin/NativeUtils"; - return registerNativeMethods(env, kClassPathName, sMethods, - sizeof(sMethods) / sizeof(sMethods[0])); -} -} // namespace latinime diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 795262aa4..1586f253b 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -21,7 +21,6 @@ #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" #include "com_android_inputmethod_latin_DicTraverseSession.h" -#include "com_android_inputmethod_latin_NativeUtils.h" #include "defines.h" #include "jni.h" #include "jni_common.h" @@ -56,11 +55,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { goto bail; } - if (!register_NativeUtils(env)) { - AKLOGE("ERROR: NativeUtils native registration failed"); - goto bail; - } - /* success -- return valid version number */ result = JNI_VERSION_1_6; diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 220171127..df1ebc0e3 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -60,14 +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(reinterpret_cast<char *>(bigramFreq) + (insertAt + 1) * sizeof(bigramFreq[0]), + reinterpret_cast<char *>(bigramFreq) + insertAt * sizeof(bigramFreq[0]), + (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); + memmove(reinterpret_cast<char *>(bigramChars) + + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short), + reinterpret_cast<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; 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..fc0a0596f 100644 --- a/native/jni/src/char_utils.cpp +++ b/native/jni/src/char_utils.cpp @@ -885,16 +885,17 @@ 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>(*reinterpret_cast<const unsigned short *>(a)) + - static_cast<int>( + (reinterpret_cast<const struct LatinCapitalSmallPair *>(b))->capital); } unsigned short latin_tolower(unsigned short c) { struct LatinCapitalSmallPair *p = - (struct LatinCapitalSmallPair *)bsearch(&c, SORTED_CHAR_MAP, + reinterpret_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..2432b1f2e 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 = reinterpret_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/com_android_inputmethod_latin_NativeUtils.h b/native/jni/src/dic_traverse_wrapper.cpp index d1ffb8f4a..1f7dcbfb2 100644 --- a/native/jni/com_android_inputmethod_latin_NativeUtils.h +++ b/native/jni/src/dic_traverse_wrapper.cpp @@ -14,14 +14,13 @@ * limitations under the License. */ -#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H -#define _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H +#define LOG_TAG "LatinIME: jni: Session" -#include "jni.h" +#include "dic_traverse_wrapper.h" namespace latinime { - -int register_NativeUtils(JNIEnv *env); - +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 -#endif // _COM_ANDROID_INPUTMETHOD_LATIN_NATIVEUTILS_H 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 8c785a263..9e4bd15a9 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(reinterpret_cast<unsigned char *>(dict)), + mOffsetDict((reinterpret_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() { @@ -64,7 +63,8 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSessi int *frequencies, int *spaceIndices, int *outputTypes) { int result = 0; if (isGesture) { - mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); + DicTraverseWrapper::initDicTraverseSession( + traverseSession, this, prevWordChars, prevWordLength); result = mGestureDecoder->getSuggestions(proximityInfo, traverseSession, xcoordinates, ycoordinates, times, pointerIds, codes, codesSize, commitPoint, outWords, frequencies, spaceIndices, outputTypes); diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 2c79527be..3b55e5de9 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -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; } + void *getDict() const { // required to release dictionary buffer + return reinterpret_cast<void *>(const_cast<unsigned char *>(mDict)); + } + void *getOffsetDict() const { + return reinterpret_cast<void *>(const_cast<unsigned char *>(mOffsetDict)); + } int getDictSize() const { return mDictSize; } int getMmapFd() const { return mMmapFd; } int getDictBufAdjust() const { return mDictBufAdjust; } @@ -68,6 +73,7 @@ class Dictionary { private: DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary); const unsigned char *mDict; + const unsigned char *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..deb042525 --- /dev/null +++ b/native/jni/src/geometry_utils.h @@ -0,0 +1,103 @@ +/* + * 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 getNormalizedSquaredDistanceFloat(float x1, float y1, float x2, float y2, + float scale) { + return squareFloat((x1 - x2) / scale) + squareFloat((y1 - y2) / scale); +} + +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 b70c8e0a3..f8bfe7c79 100644 --- a/native/jni/src/gesture/gesture_decoder_wrapper.h +++ b/native/jni/src/gesture/gesture_decoder_wrapper.h @@ -48,35 +48,13 @@ class GestureDecoderWrapper : public IncrementalDecoderInterface { 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); - } - static void setGestureDecoderFactoryMethod( IncrementalDecoderInterface *(*factoryMethod)(int, int)) { sGestureDecoderFactoryMethod = factoryMethod; } 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 e8d3a5333..04f0095e0 100644 --- a/native/jni/src/gesture/incremental_decoder_interface.h +++ b/native/jni/src/gesture/incremental_decoder_interface.h @@ -32,11 +32,10 @@ class IncrementalDecoderInterface { 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; + 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 8d66b4ec1..5cb2ee368 100644 --- a/native/jni/src/gesture/incremental_decoder_wrapper.h +++ b/native/jni/src/gesture/incremental_decoder_wrapper.h @@ -48,35 +48,13 @@ class IncrementalDecoderWrapper : public IncrementalDecoderInterface { 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); - } - static void setIncrementalDecoderFactoryMethod( IncrementalDecoderInterface *(*factoryMethod)(int, int)) { sIncrementalDecoderFactoryMethod = factoryMethod; } 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 2564c8a67..ade78a1ec 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -23,6 +23,7 @@ #include "additional_proximity_chars.h" #include "char_utils.h" #include "defines.h" +#include "geometry_utils.h" #include "jni.h" #include "proximity_info.h" @@ -33,7 +34,7 @@ static inline void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray if (jArray && buffer) { env->GetIntArrayRegion(jArray, 0, len, buffer); } else if (buffer) { - memset(buffer, 0, len); + memset(buffer, 0, len * sizeof(jint)); } } @@ -42,7 +43,7 @@ static inline void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jA if (jArray && buffer) { env->GetFloatArrayRegion(jArray, 0, len, buffer); } else if (buffer) { - memset(buffer, 0, len); + memset(buffer, 0, len * sizeof(jfloat)); } } @@ -55,6 +56,7 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma 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), @@ -84,6 +86,7 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma 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, @@ -222,11 +225,72 @@ int ProximityInfo::getKeyIndex(const int c) const { return mCodeToKeyIndex[baseLowerC]; } +int ProximityInfo::getKeyCode(const int keyIndex) const { + if (keyIndex < 0 || keyIndex >= KEY_COUNT) { + return NOT_AN_INDEX; + } + return mKeyToCodeIndexG[keyIndex]; +} + +void ProximityInfo::initializeG() { + for (int i = 0; i < KEY_COUNT; ++i) { + const int code = mKeyCharCodes[i]; + const int lowerCode = toBaseLowerCase(code); + mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2; + mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2; + if (code != lowerCode && lowerCode >= 0 && lowerCode <= MAX_CHAR_CODE) { + mCodeToKeyIndex[lowerCode] = i; + mKeyToCodeIndexG[i] = lowerCode; + } else { + 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; +} + // 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)); + *keyWidth = sqrtf(static_cast<float>(MOST_COMMON_KEY_WIDTH_SQUARE)); for (int i = 0; i < KEY_COUNT; ++i) { const int code = mKeyCharCodes[i]; diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index d7e24c5f5..58f2d7502 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -49,6 +49,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,6 +71,10 @@ 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; } @@ -98,6 +103,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 +124,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,6 +135,7 @@ 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; @@ -139,6 +152,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..e97e16a12 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,13 @@ class WordsPriorityQueue { continue; } const unsigned int wordLength = sw->mWordLength; - char *targetAdr = (char*) outputChars + i * MAX_WORD_LENGTH * sizeof(short); + char *targetAddress = reinterpret_cast<char *>(outputChars) + + i * MAX_WORD_LENGTH * sizeof(short); frequencies[i] = sw->mScore; - memcpy(targetAdr, sw->mWord, (wordLength) * sizeof(short)); + outputTypes[i] = sw->mType; + memcpy(targetAddress, sw->mWord, (wordLength) * sizeof(short)); if (wordLength < MAX_WORD_LENGTH) { - ((unsigned short*) targetAdr)[wordLength] = 0; + reinterpret_cast<unsigned short *>(targetAddress)[wordLength] = 0; } sw->mUsed = false; } @@ -191,10 +195,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]; } } |