aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CleanSpec.mk1
-rw-r--r--java/res/values/config.xml6
-rw-r--r--java/res/xml/kbd_rows_number.xml2
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java71
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/Flag.java15
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java77
-rw-r--r--native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp16
-rw-r--r--native/jni/jni_common.h14
-rw-r--r--native/src/correction.cpp14
-rw-r--r--native/src/correction.h3
-rw-r--r--native/src/defines_touch_position_correction.h61
-rw-r--r--native/src/proximity_info.cpp33
-rw-r--r--native/src/proximity_info.h15
-rw-r--r--native/src/unigram_dictionary.cpp30
-rw-r--r--native/src/unigram_dictionary.h15
17 files changed, 218 insertions, 159 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 505e41b49..c274a6c44 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -50,6 +50,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/LatinIME.apk)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 999247839..bcce58123 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -82,8 +82,10 @@
will be subject to auto-correction. -->
<item>0</item>
</string-array>
- <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare a word to be a typo -->
- <string name="spellchecker_typo_threshold_value" translatable="false">0.11</string>
+ <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare a word to be "likely" -->
+ <string name="spellchecker_likely_threshold_value" translatable="false">0.11</string>
+ <!-- Threshold of the normalized score of any dictionary lookup to be offered as a suggestion by the spell checker -->
+ <string name="spellchecker_suggestion_threshold_value" translatable="false">0.03</string>
<!-- Screen metrics for logging.
0 = "mdpi phone screen"
1 = "hdpi phone screen"
diff --git a/java/res/xml/kbd_rows_number.xml b/java/res/xml/kbd_rows_number.xml
index 21d0656d1..90ac5686b 100644
--- a/java/res/xml/kbd_rows_number.xml
+++ b/java/res/xml/kbd_rows_number.xml
@@ -36,6 +36,7 @@
latin:keyStyle="num2KeyStyle" />
<Key
latin:keyStyle="num3KeyStyle" />
+ <Spacer />
</Row>
<Row>
<Key
@@ -44,6 +45,7 @@
latin:keyStyle="num5KeyStyle" />
<Key
latin:keyStyle="num6KeyStyle" />
+ <Spacer />
</Row>
<Row>
<Key
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index f77155ee3..9e4c1ea79 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -138,7 +138,7 @@ public class Keyboard {
mProximityInfo = new ProximityInfo(
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
- mMostCommonKeyWidth, mKeys, params.mTouchPositionCorrectionXs,
+ mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs,
params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii);
}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 210ab48a1..d35b1a939 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.keyboard;
+import android.graphics.Rect;
+
+import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
@@ -27,9 +30,9 @@ public class ProximityInfo {
public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
/** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.2f;
- private static final int UNKNOWN_THEME = -1;
private static final int[] EMPTY_INT_ARRAY = new int[0];
+ private final int mKeyHeight;
private final int mGridWidth;
private final int mGridHeight;
private final int mGridSize;
@@ -45,8 +48,8 @@ public class ProximityInfo {
private final float[] mTouchPositionCorrectionRadii;
ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
- List<Key> keys, float[] touchPositionCorrectionXs, float[] touchPositionCorrectionYs,
- float[] touchPositionCorrectionRadii) {
+ int keyHeight, List<Key> keys, float[] touchPositionCorrectionXs,
+ float[] touchPositionCorrectionYs, float[] touchPositionCorrectionRadii) {
mGridWidth = gridWidth;
mGridHeight = gridHeight;
mGridSize = mGridWidth * mGridHeight;
@@ -54,6 +57,7 @@ public class ProximityInfo {
mCellHeight = (height + mGridHeight - 1) / mGridHeight;
mKeyboardMinWidth = minWidth;
mKeyboardHeight = height;
+ mKeyHeight = keyHeight;
mTouchPositionCorrectionXs = touchPositionCorrectionXs;
mTouchPositionCorrectionYs = touchPositionCorrectionYs;
mTouchPositionCorrectionRadii = touchPositionCorrectionRadii;
@@ -66,7 +70,7 @@ public class ProximityInfo {
}
public static ProximityInfo createDummyProximityInfo() {
- return new ProximityInfo(1, 1, 1, 1, 1, Collections.<Key>emptyList(), null, null, null);
+ return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null, null, null);
}
public static ProximityInfo createSpellCheckerProximityInfo() {
@@ -75,7 +79,7 @@ public class ProximityInfo {
spellCheckerProximityInfo.setProximityInfoNative(
SpellCheckerProximityInfo.ROW_SIZE,
480, 300, 10, 3, SpellCheckerProximityInfo.PROXIMITY,
- 0, null, null, null, null, null, UNKNOWN_THEME);
+ 0, null, null, null, null, null, null, null, null);
return spellCheckerProximityInfo;
}
@@ -86,7 +90,8 @@ public class ProximityInfo {
private native int setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray,
int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
- int[] keyWidths, int[] keyHeights, int[] keyCharCodes, int themeId);
+ int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
+ float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
private native void releaseProximityInfoNative(int nativeProximityInfo);
private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth,
@@ -101,12 +106,11 @@ public class ProximityInfo {
}
}
final int keyCount = keys.size();
- int[] keyXCoordinates = new int[keyCount];
- int[] keyYCoordinates = new int[keyCount];
- int[] keyWidths = new int[keyCount];
- int[] keyHeights = new int[keyCount];
- int[] keyCharCodes = new int[keyCount];
- final int themeId = 5; // TODO: Use real theme id.
+ final int[] keyXCoordinates = new int[keyCount];
+ final int[] keyYCoordinates = new int[keyCount];
+ final int[] keyWidths = new int[keyCount];
+ final int[] keyHeights = new int[keyCount];
+ final int[] keyCharCodes = new int[keyCount];
for (int i = 0; i < keyCount; ++i) {
final Key key = keys.get(i);
keyXCoordinates[i] = key.mX;
@@ -115,10 +119,51 @@ public class ProximityInfo {
keyHeights[i] = key.mHeight;
keyCharCodes[i] = key.mCode;
}
+
+ final boolean hasTouchPositionCorrectionData =
+ mTouchPositionCorrectionXs != null
+ && mTouchPositionCorrectionYs != null
+ && mTouchPositionCorrectionRadii != null
+ && mTouchPositionCorrectionXs.length > 0
+ && mTouchPositionCorrectionYs.length > 0
+ && mTouchPositionCorrectionRadii.length > 0;
+ final float[] sweetSpotCenterXs =
+ hasTouchPositionCorrectionData ? new float[keyCount] : null;
+ final float[] sweetSpotCenterYs =
+ hasTouchPositionCorrectionData ? new float[keyCount] : null;
+ final float[] sweetSpotRadii =
+ hasTouchPositionCorrectionData ? new float[keyCount] : null;
+ if (hasTouchPositionCorrectionData) {
+ calculateSweetSpot(keys, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ }
+
mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE,
keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray,
keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
- themeId);
+ sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ }
+
+ private void calculateSweetSpot(List<Key> keys, float[] sweetSpotCenterXs,
+ float[] sweetSpotCenterYs, float[] sweetSpotRadii) {
+ final int keyCount = keys.size();
+ for (int i = 0; i < keyCount; ++i) {
+ final Key key = keys.get(i);
+ final Rect hitBox = key.mHitBox;
+ final int row = hitBox.top / mKeyHeight;
+ if (row < mTouchPositionCorrectionRadii.length) {
+ final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
+ final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
+ final float hitBoxWidth = hitBox.right - hitBox.left;
+ final float hitBoxHeight = hitBox.bottom - hitBox.top;
+ final float x = mTouchPositionCorrectionXs[row];
+ final float y = mTouchPositionCorrectionYs[row];
+ final float radius = mTouchPositionCorrectionRadii[row];
+ sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
+ sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
+ sweetSpotRadii[i] = radius
+ * (float)Math.sqrt(hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
+ }
+ }
}
public int getNativeProximityInfo() {
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 6a6a0a4ee..ab9edb110 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -61,6 +61,8 @@ public class BinaryDictionary extends Dictionary {
public static final Flag FLAG_REQUIRES_GERMAN_UMLAUT_PROCESSING =
new Flag(R.bool.config_require_umlaut_processing, 0x1);
+ public static final Flag FLAG_USE_FULL_EDIT_DISTANCE = new Flag(0x2);
+
// Can create a new flag from extravalue :
// public static final Flag FLAG_MYFLAG =
// new Flag("my_flag", 0x02);
diff --git a/java/src/com/android/inputmethod/latin/Flag.java b/java/src/com/android/inputmethod/latin/Flag.java
index 3cb8f7e17..4ba6c80f5 100644
--- a/java/src/com/android/inputmethod/latin/Flag.java
+++ b/java/src/com/android/inputmethod/latin/Flag.java
@@ -25,8 +25,9 @@ public class Flag {
public final int mMask;
public final int mSource;
- static private final int SOURCE_CONFIG = 1;
- static private final int SOURCE_EXTRAVALUE = 2;
+ private static final int SOURCE_CONFIG = 1;
+ private static final int SOURCE_EXTRAVALUE = 2;
+ private static final int SOURCE_PARAM = 3;
public Flag(int resourceId, int mask) {
mName = null;
@@ -42,6 +43,13 @@ public class Flag {
mMask = mask;
}
+ public Flag(int mask) {
+ mName = null;
+ mResource = 0;
+ mSource = SOURCE_PARAM;
+ mMask = mask;
+ }
+
// If context/switcher are null, set all related flags in flagArray to on.
public static int initFlags(Flag[] flagArray, Context context, SubtypeSwitcher switcher) {
int flags = 0;
@@ -57,6 +65,9 @@ public class Flag {
switcher.currentSubtypeContainsExtraValueKey(entry.mName))
flags |= entry.mMask;
break;
+ case Flag.SOURCE_PARAM:
+ flags |= entry.mMask;
+ break;
}
}
return flags;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 37145b257..1d5986ef9 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -70,11 +70,17 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
private Map<String, Dictionary> mUserDictionaries =
Collections.synchronizedMap(new TreeMap<String, Dictionary>());
- private double mTypoThreshold;
+ // The threshold for a candidate to be offered as a suggestion.
+ private double mSuggestionThreshold;
+ // The threshold for a suggestion to be considered "likely".
+ private double mLikelyThreshold;
@Override public void onCreate() {
super.onCreate();
- mTypoThreshold = Double.parseDouble(getString(R.string.spellchecker_typo_threshold_value));
+ mSuggestionThreshold =
+ Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value));
+ mLikelyThreshold =
+ Double.parseDouble(getString(R.string.spellchecker_likely_threshold_value));
}
@Override
@@ -96,7 +102,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
private final ArrayList<CharSequence> mSuggestions;
private final int[] mScores;
private final String mOriginalText;
- private final double mThreshold;
+ private final double mSuggestionThreshold;
+ private final double mLikelyThreshold;
private final int mMaxLength;
private int mLength = 0;
@@ -105,10 +112,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
private String mBestSuggestion = null;
private int mBestScore = Integer.MIN_VALUE; // As small as possible
- SuggestionsGatherer(final String originalText, final double threshold,
- final int maxLength) {
+ SuggestionsGatherer(final String originalText, final double suggestionThreshold,
+ final double likelyThreshold, final int maxLength) {
mOriginalText = originalText;
- mThreshold = threshold;
+ mSuggestionThreshold = suggestionThreshold;
+ mLikelyThreshold = likelyThreshold;
mMaxLength = maxLength;
mSuggestions = new ArrayList<CharSequence>(maxLength + 1);
mScores = new int[mMaxLength];
@@ -122,28 +130,42 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
// if it doesn't. See documentation for binarySearch.
final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1;
+ if (insertIndex == 0 && mLength >= mMaxLength) {
+ // In the future, we may want to keep track of the best suggestion score even if
+ // we are asked for 0 suggestions. In this case, we can use the following
+ // (tested) code to keep it:
+ // If the maxLength is 0 (should never be less, but if it is, it's treated as 0)
+ // then we need to keep track of the best suggestion in mBestScore and
+ // mBestSuggestion. This is so that we know whether the best suggestion makes
+ // the score cutoff, since we need to know that to return a meaningful
+ // looksLikeTypo.
+ // if (0 >= mMaxLength) {
+ // if (score > mBestScore) {
+ // mBestScore = score;
+ // mBestSuggestion = new String(word, wordOffset, wordLength);
+ // }
+ // }
+ return true;
+ }
+
+ // Compute the normalized score and skip this word if it's normalized score does not
+ // make the threshold.
+ final String wordString = new String(word, wordOffset, wordLength);
+ final double normalizedScore =
+ Utils.calcNormalizedScore(mOriginalText, wordString, score);
+ if (normalizedScore < mSuggestionThreshold) {
+ if (DBG) Log.i(TAG, wordString + " does not make the score threshold");
+ return true;
+ }
+
if (mLength < mMaxLength) {
final int copyLen = mLength - insertIndex;
++mLength;
System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen);
- mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
+ mSuggestions.add(insertIndex, wordString);
} else {
- if (insertIndex == 0) {
- // If the maxLength is 0 (should never be less, but if it is, it's treated as 0)
- // then we need to keep track of the best suggestion in mBestScore and
- // mBestSuggestion. This is so that we know whether the best suggestion makes
- // the score cutoff, since we need to know that to return a meaningful
- // looksLikeTypo.
- if (0 >= mMaxLength) {
- if (score > mBestScore) {
- mBestScore = score;
- mBestSuggestion = new String(word, wordOffset, wordLength);
- }
- }
- return true;
- }
System.arraycopy(mScores, 1, mScores, 0, insertIndex);
- mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
+ mSuggestions.add(insertIndex, wordString);
mSuggestions.remove(0);
}
mScores[insertIndex] = score;
@@ -165,7 +187,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
gatheredSuggestions = EMPTY_STRING_ARRAY;
final double normalizedScore =
Utils.calcNormalizedScore(mOriginalText, mBestSuggestion, mBestScore);
- hasLikelySuggestions = (normalizedScore > mThreshold);
+ hasLikelySuggestions = (normalizedScore > mLikelyThreshold);
}
} else {
if (DBG) {
@@ -199,10 +221,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
final CharSequence bestSuggestion = mSuggestions.get(0);
final double normalizedScore =
Utils.calcNormalizedScore(mOriginalText, bestSuggestion, bestScore);
- hasLikelySuggestions = (normalizedScore > mThreshold);
+ hasLikelySuggestions = (normalizedScore > mLikelyThreshold);
if (DBG) {
Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore);
- Log.i(TAG, "Normalized score = " + normalizedScore + " (threshold " + mThreshold
+ Log.i(TAG, "Normalized score = " + normalizedScore
+ + " (threshold " + mLikelyThreshold
+ ") => hasLikelySuggestions = " + hasLikelySuggestions);
}
}
@@ -354,8 +377,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
}
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
- final SuggestionsGatherer suggestionsGatherer =
- new SuggestionsGatherer(text, mService.mTypoThreshold, suggestionsLimit);
+ final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text,
+ mService.mSuggestionThreshold, mService.mLikelyThreshold, suggestionsLimit);
final WordComposer composer = new WordComposer();
final int length = text.length();
for (int i = 0; i < length; ++i) {
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
index 07cee4053..595ea2fdc 100644
--- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
@@ -32,18 +32,27 @@ static jint latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object,
jint maxProximityCharsSize, jint displayWidth, jint displayHeight, jint gridWidth,
jint gridHeight, jintArray proximityCharsArray, jint keyCount,
jintArray keyXCoordinateArray, jintArray keyYCoordinateArray, jintArray keyWidthArray,
- jintArray keyHeightArray, jintArray keyCharCodeArray, jint themeId) {
+ jintArray keyHeightArray, jintArray keyCharCodeArray,
+ jfloatArray sweetSpotCenterXArray, jfloatArray sweetSpotCenterYArray,
+ jfloatArray sweetSpotRadiusArray) {
jint *proximityChars = env->GetIntArrayElements(proximityCharsArray, NULL);
jint *keyXCoordinates = safeGetIntArrayElements(env, keyXCoordinateArray);
jint *keyYCoordinates = safeGetIntArrayElements(env, keyYCoordinateArray);
jint *keyWidths = safeGetIntArrayElements(env, keyWidthArray);
jint *keyHeights = safeGetIntArrayElements(env, keyHeightArray);
jint *keyCharCodes = safeGetIntArrayElements(env, keyCharCodeArray);
+ jfloat *sweetSpotCenterXs = safeGetFloatArrayElements(env, sweetSpotCenterXArray);
+ jfloat *sweetSpotCenterYs = safeGetFloatArrayElements(env, sweetSpotCenterYArray);
+ jfloat *sweetSpotRadii = safeGetFloatArrayElements(env, sweetSpotRadiusArray);
ProximityInfo *proximityInfo = new ProximityInfo(maxProximityCharsSize, displayWidth,
displayHeight, gridWidth, gridHeight, (const uint32_t*)proximityChars,
keyCount, (const int32_t*)keyXCoordinates, (const int32_t*)keyYCoordinates,
(const int32_t*)keyWidths, (const int32_t*)keyHeights, (const int32_t*)keyCharCodes,
- themeId);
+ (const float*)sweetSpotCenterXs, (const float*)sweetSpotCenterYs,
+ (const float*)sweetSpotRadii);
+ safeReleaseFloatArrayElements(env, sweetSpotRadiusArray, sweetSpotRadii);
+ safeReleaseFloatArrayElements(env, sweetSpotCenterYArray, sweetSpotCenterYs);
+ safeReleaseFloatArrayElements(env, sweetSpotCenterXArray, sweetSpotCenterXs);
safeReleaseIntArrayElements(env, keyCharCodeArray, keyCharCodes);
safeReleaseIntArrayElements(env, keyHeightArray, keyHeights);
safeReleaseIntArrayElements(env, keyWidthArray, keyWidths);
@@ -60,7 +69,8 @@ static void latinime_Keyboard_release(JNIEnv *env, jobject object, jint proximit
}
static JNINativeMethod sKeyboardMethods[] = {
- {"setProximityInfoNative", "(IIIII[II[I[I[I[I[II)I", (void*)latinime_Keyboard_setProximityInfo},
+ {"setProximityInfoNative", "(IIIII[II[I[I[I[I[I[F[F[F)I",
+ (void*)latinime_Keyboard_setProximityInfo},
{"releaseProximityInfoNative", "(I)V", (void*)latinime_Keyboard_release}
};
diff --git a/native/jni/jni_common.h b/native/jni/jni_common.h
index dbf6d3e19..9548e1b3f 100644
--- a/native/jni/jni_common.h
+++ b/native/jni/jni_common.h
@@ -35,12 +35,26 @@ inline jint *safeGetIntArrayElements(JNIEnv *env, jintArray jArray) {
}
}
+inline jfloat *safeGetFloatArrayElements(JNIEnv *env, jfloatArray jArray) {
+ if (jArray) {
+ return env->GetFloatArrayElements(jArray, NULL);
+ } else {
+ return NULL;
+ }
+}
+
inline void safeReleaseIntArrayElements(JNIEnv *env, jintArray jArray, jint *cArray) {
if (jArray) {
env->ReleaseIntArrayElements(jArray, cArray, 0);
}
}
+inline void safeReleaseFloatArrayElements(JNIEnv *env, jfloatArray jArray, jfloat *cArray) {
+ if (jArray) {
+ env->ReleaseFloatArrayElements(jArray, cArray, 0);
+ }
+}
+
} // namespace latinime
#endif // LATINIME_JNI_COMMON_H
diff --git a/native/src/correction.cpp b/native/src/correction.cpp
index d5bfed017..9a7e5f35d 100644
--- a/native/src/correction.cpp
+++ b/native/src/correction.cpp
@@ -62,7 +62,8 @@ void Correction::initCorrectionState(
}
void Correction::setCorrectionParams(const int skipPos, const int excessivePos,
- const int transposedPos, const int spaceProximityPos, const int missingSpacePos) {
+ const int transposedPos, const int spaceProximityPos, const int missingSpacePos,
+ const bool useFullEditDistance) {
// TODO: remove
mTransposedPos = transposedPos;
mExcessivePos = excessivePos;
@@ -74,6 +75,7 @@ void Correction::setCorrectionParams(const int skipPos, const int excessivePos,
mSpaceProximityPos = spaceProximityPos;
mMissingSpacePos = missingSpacePos;
+ mUseFullEditDistance = useFullEditDistance;
}
void Correction::checkState() {
@@ -439,7 +441,7 @@ inline static void multiplyIntCapped(const int multiplier, int *base) {
}
inline static int powerIntCapped(const int base, const int n) {
- if (n == 0) return 1;
+ if (n <= 0) return 1;
if (base == 2) {
return n < 31 ? 1 << n : S_INT_MAX;
} else {
@@ -529,6 +531,8 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const
const int excessiveCount = correction->mExcessiveCount + correction->mTransposedCount % 2;
const int proximityMatchedCount = correction->mProximityCount;
const bool lastCharExceeded = correction->mLastCharExceeded;
+ const bool useFullEditDistance = correction->mUseFullEditDistance;
+ const int outputLength = outputIndex + 1;
if (skippedCount >= inputLength || inputLength == 0) {
return -1;
}
@@ -682,6 +686,12 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const
multiplyIntCapped(fullWordMultiplier, &finalFreq);
}
+ if (useFullEditDistance && outputLength > inputLength + 1) {
+ const int diff = outputLength - inputLength - 1;
+ const int divider = diff < 31 ? 1 << diff : S_INT_MAX;
+ finalFreq = divider > finalFreq ? 1 : finalFreq / divider;
+ }
+
if (DEBUG_DICT_FULL) {
LOGI("calc: %d, %d", outputIndex, sameLength);
}
diff --git a/native/src/correction.h b/native/src/correction.h
index 41130ad77..ddb98b9d8 100644
--- a/native/src/correction.h
+++ b/native/src/correction.h
@@ -44,7 +44,7 @@ public:
// TODO: remove
void setCorrectionParams(const int skipPos, const int excessivePos, const int transposedPos,
- const int spaceProximityPos, const int missingSpacePos);
+ const int spaceProximityPos, const int missingSpacePos, const bool useFullEditDistance);
void checkState();
bool initProcessState(const int index);
@@ -111,6 +111,7 @@ private:
const int FULL_WORD_MULTIPLIER;
const ProximityInfo *mProximityInfo;
+ bool mUseFullEditDistance;
int mMaxEditDistance;
int mMaxDepth;
int mInputLength;
diff --git a/native/src/defines_touch_position_correction.h b/native/src/defines_touch_position_correction.h
deleted file mode 100644
index 122906804..000000000
--- a/native/src/defines_touch_position_correction.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-**
-** Copyright 2011, 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_DEFINES_TOUCH_POSITION_CORRECTION_H
-#define LATINIME_DEFINES_TOUCH_POSITION_CORRECTION_H
-
-#define OUTER_SWEET_SPOT_RADIUS_RATIO 1.3
-
-static const char* TOUCH_POSITION_CORRECTION_GROUPS[] = {
- "qwertyuiop",
- "a",
- "sdfghjk",
- "l",
- "zxcvbnm",
-};
-
-// (center X) / (key width)
-static const float RELATIVE_TOUCH_CENTER_X[] = {
- 0, // qwertyuiop
- -0.26871, // a
- 0, // sdfghjk
- 0.028050, // l
- 0, // zxcvbnm
-};
-
-// (center Y) / (key height)
-static const float RELATIVE_TOUCH_CENTER_Y[] = {
- 0.192088, // qwertyuiop
- 0.214100, // a
- 0.216640, // sdfghjk
- 0.233288, // l
- 0.286598, // zxcvbnm
-};
-
-// (sweet spot radius) / ((key width) + (key height))
-static const float SWEET_SPOT_RADIUS[] = {
- 0.148955, // qwertyuiop
- 0.185437, // a
- 0.145522, // sdfghjk
- 0.156882, // l
- 0.144211, // zxcvbnm
-};
-
-#define CORRECTION_GROUP_COUNT \
- ((int)(sizeof(TOUCH_POSITION_CORRECTION_GROUPS) / sizeof(TOUCH_POSITION_CORRECTION_GROUPS[0])))
-
-#endif // LATINIME_DEFINES_TOUCH_POSITION_CORRECTION_H
diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp
index 58842b92f..4ff6e0ac0 100644
--- a/native/src/proximity_info.cpp
+++ b/native/src/proximity_info.cpp
@@ -20,7 +20,6 @@
#define LOG_TAG "LatinIME: proximity_info.cpp"
-#include "defines_touch_position_correction.h"
#include "dictionary.h"
#include "proximity_info.h"
@@ -38,12 +37,13 @@ ProximityInfo::ProximityInfo(const int maxProximityCharsSize, const int keyboard
const int keyboardHeight, const int gridWidth, const int gridHeight,
const uint32_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, int themeId)
+ const int32_t *keyCharCodes, const float *sweetSpotCenterXs, const float *sweetSpotCenterYs,
+ const float *sweetSpotRadii)
: MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth),
KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight),
CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
- KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), THEME_ID(themeId) {
+ KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)) {
const int len = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
mProximityCharsArray = new uint32_t[len];
if (DEBUG_PROXIMITY_INFO) {
@@ -56,33 +56,24 @@ ProximityInfo::ProximityInfo(const int maxProximityCharsSize, const int keyboard
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]));
- initializeCodeToGroup();
initializeCodeToKeyIndex();
}
-// Build the reversed look up table from the char code to the index in its group.
-// see TOUCH_POSITION_CORRECTION_GROUPS
-void ProximityInfo::initializeCodeToGroup() {
- memset(mCodeToGroup, -1, (MAX_GROUPED_CHAR_CODE + 1) * sizeof(mCodeToGroup[0]));
- for (int i = 0; i < CORRECTION_GROUP_COUNT; ++i) {
- const char *group = TOUCH_POSITION_CORRECTION_GROUPS[i];
- for (int j = 0; group[j]; ++j) {
- const int code = group[j];
- if (0 <= code && code <= MAX_GROUPED_CHAR_CODE)
- mCodeToGroup[code] = i;
- }
- }
-}
-
// Build the reversed look up table from the char code to the index in mKeyXCoordinates,
// mKeyYCoordinates, mKeyWidths, mKeyHeights, mKeyCharCodes.
void ProximityInfo::initializeCodeToKeyIndex() {
- memset(mCodeToKeyIndex, -1, (MAX_GROUPED_CHAR_CODE + 1) * sizeof(mCodeToKeyIndex[0]));
+ memset(mCodeToKeyIndex, -1, (MAX_CHAR_CODE + 1) * sizeof(mCodeToKeyIndex[0]));
for (int i = 0; i < KEY_COUNT; ++i) {
const int code = mKeyCharCodes[i];
- if (0 <= code && code <= MAX_GROUPED_CHAR_CODE)
+ if (0 <= code && code <= MAX_CHAR_CODE) {
mCodeToKeyIndex[code] = i;
+ }
}
}
@@ -210,6 +201,6 @@ bool ProximityInfo::sameAsTyped(const unsigned short *word, int length) const {
}
const int ProximityInfo::MAX_KEY_COUNT_IN_A_KEYBOARD;
-const int ProximityInfo::MAX_GROUPED_CHAR_CODE;
+const int ProximityInfo::MAX_CHAR_CODE;
} // namespace latinime
diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h
index 3190e73ef..b1e8236d3 100644
--- a/native/src/proximity_info.h
+++ b/native/src/proximity_info.h
@@ -37,7 +37,8 @@ public:
const int keybaordHeight, const int gridWidth, const int gridHeight,
const uint32_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, int themeId);
+ const int32_t *keyCharCodes, const float *sweetSpotCenterXs,
+ const float *sweetSpotCenterYs, const float *sweetSpotRadii);
~ProximityInfo();
bool hasSpaceProximity(const int x, const int y) const;
void setInputParams(const int* inputCodes, const int inputLength);
@@ -55,11 +56,10 @@ public:
private:
// The max number of the keys in one keyboard layout
static const int MAX_KEY_COUNT_IN_A_KEYBOARD = 64;
- // The upper limit of the char code in TOUCH_POSITION_CORRECTION_GROUP
- static const int MAX_GROUPED_CHAR_CODE = 127;
+ // The upper limit of the char code in mCodeToKeyIndex
+ static const int MAX_CHAR_CODE = 127;
int getStartIndexFromCoordinates(const int x, const int y) const;
- void initializeCodeToGroup();
void initializeCodeToKeyIndex();
const int MAX_PROXIMITY_CHARS_SIZE;
const int KEYBOARD_WIDTH;
@@ -69,7 +69,6 @@ private:
const int CELL_WIDTH;
const int CELL_HEIGHT;
const int KEY_COUNT;
- const int THEME_ID;
const int *mInputCodes;
uint32_t *mProximityCharsArray;
int32_t mKeyXCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD];
@@ -77,10 +76,12 @@ private:
int32_t mKeyWidths[MAX_KEY_COUNT_IN_A_KEYBOARD];
int32_t mKeyHeights[MAX_KEY_COUNT_IN_A_KEYBOARD];
int32_t mKeyCharCodes[MAX_KEY_COUNT_IN_A_KEYBOARD];
+ float mSweetSpotCenterXs[MAX_KEY_COUNT_IN_A_KEYBOARD];
+ float mSweetSpotCenterYs[MAX_KEY_COUNT_IN_A_KEYBOARD];
+ float mSweetSpotRadii[MAX_KEY_COUNT_IN_A_KEYBOARD];
int mInputLength;
unsigned short mPrimaryInputWord[MAX_WORD_LENGTH_INTERNAL];
- int mCodeToGroup[MAX_GROUPED_CHAR_CODE + 1];
- int mCodeToKeyIndex[MAX_GROUPED_CHAR_CODE + 1];
+ int mCodeToKeyIndex[MAX_CHAR_CODE + 1];
};
} // namespace latinime
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index 517dc843e..1b798a8f1 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -132,7 +132,8 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit
memcpy(codesDest, codesSrc, remainingBytes);
getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
- (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, outWords, frequencies);
+ (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, outWords, frequencies,
+ flags);
}
int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
@@ -146,7 +147,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x
codesSize, flags, codes, codesSize, 0, codesBuffer, outWords, frequencies);
} else { // Normal processing
getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize,
- outWords, frequencies);
+ outWords, frequencies, flags);
}
PROF_START(20);
@@ -175,7 +176,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x
void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize,
- unsigned short *outWords, int *frequencies) {
+ unsigned short *outWords, int *frequencies, const int flags) {
PROF_OPEN;
PROF_START(0);
@@ -187,9 +188,10 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
mCorrection->initCorrection(mProximityInfo, mInputLength, maxDepth);
PROF_END(0);
+ const bool useFullEditDistance = USE_FULL_EDIT_DISTANCE & flags;
// TODO: remove
PROF_START(1);
- getSuggestionCandidates();
+ getSuggestionCandidates(useFullEditDistance);
PROF_END(1);
PROF_START(2);
@@ -212,7 +214,7 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
if (DEBUG_DICT) {
LOGI("--- Suggest missing space characters %d", i);
}
- getMissingSpaceWords(mInputLength, i, mCorrection);
+ getMissingSpaceWords(mInputLength, i, mCorrection, useFullEditDistance);
}
}
PROF_END(5);
@@ -231,7 +233,7 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo,
i, x, y, proximityInfo->hasSpaceProximity(x, y));
}
if (proximityInfo->hasSpaceProximity(x, y)) {
- getMistypedSpaceWords(mInputLength, i, mCorrection);
+ getMistypedSpaceWords(mInputLength, i, mCorrection, useFullEditDistance);
}
}
}
@@ -315,10 +317,10 @@ bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency)
static const char QUOTE = '\'';
static const char SPACE = ' ';
-void UnigramDictionary::getSuggestionCandidates() {
+void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance) {
// TODO: Remove setCorrectionParams
mCorrection->setCorrectionParams(0, 0, 0,
- -1 /* spaceProximityPos */, -1 /* missingSpacePos */);
+ -1 /* spaceProximityPos */, -1 /* missingSpacePos */, useFullEditDistance);
int rootPosition = ROOT_POS;
// Get the number of children of root, then increment the position
int childCount = Dictionary::getCount(DICT_ROOT, &rootPosition);
@@ -349,16 +351,20 @@ void UnigramDictionary::getSuggestionCandidates() {
}
void UnigramDictionary::getMissingSpaceWords(
- const int inputLength, const int missingSpacePos, Correction *correction) {
+ const int inputLength, const int missingSpacePos, Correction *correction,
+ const bool useFullEditDistance) {
correction->setCorrectionParams(-1 /* skipPos */, -1 /* excessivePos */,
- -1 /* transposedPos */, -1 /* spaceProximityPos */, missingSpacePos);
+ -1 /* transposedPos */, -1 /* spaceProximityPos */, missingSpacePos,
+ useFullEditDistance);
getSplitTwoWordsSuggestion(inputLength, correction);
}
void UnigramDictionary::getMistypedSpaceWords(
- const int inputLength, const int spaceProximityPos, Correction *correction) {
+ const int inputLength, const int spaceProximityPos, Correction *correction,
+ const bool useFullEditDistance) {
correction->setCorrectionParams(-1 /* skipPos */, -1 /* excessivePos */,
- -1 /* transposedPos */, spaceProximityPos, -1 /* missingSpacePos */);
+ -1 /* transposedPos */, spaceProximityPos, -1 /* missingSpacePos */,
+ useFullEditDistance);
getSplitTwoWordsSuggestion(inputLength, correction);
}
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index 65746db8d..ef9709a89 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -78,7 +78,7 @@ private:
void getWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const int codesSize,
- unsigned short *outWords, int *frequencies);
+ unsigned short *outWords, int *frequencies, const int flags);
bool isDigraph(const int* codes, const int i, const int codesSize) const;
void getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo,
const int *xcoordinates, const int* ycoordinates, const int *codesBuffer,
@@ -87,13 +87,13 @@ private:
void initSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const int codesSize,
unsigned short *outWords, int *frequencies);
- void getSuggestionCandidates();
+ void getSuggestionCandidates(const bool useFullEditDistance);
bool addWord(unsigned short *word, int length, int frequency);
void getSplitTwoWordsSuggestion(const int inputLength, Correction *correction);
- void getMissingSpaceWords(
- const int inputLength, const int missingSpacePos, Correction *correction);
- void getMistypedSpaceWords(
- const int inputLength, const int spaceProximityPos, Correction *correction);
+ void getMissingSpaceWords(const int inputLength, const int missingSpacePos,
+ Correction *correction, const bool useFullEditDistance);
+ void getMistypedSpaceWords(const int inputLength, const int spaceProximityPos,
+ Correction *correction, const bool useFullEditDistance);
void onTerminal(const int freq, Correction *correction);
bool needsToSkipCurrentNode(const unsigned short c,
const int inputIndex, const int skipPos, const int depth);
@@ -122,7 +122,8 @@ private:
// or something very bad (like, the apocalypse) will happen.
// Please update both at the same time.
enum {
- REQUIRES_GERMAN_UMLAUT_PROCESSING = 0x1
+ REQUIRES_GERMAN_UMLAUT_PROCESSING = 0x1,
+ USE_FULL_EDIT_DISTANCE = 0x2
};
static const struct digraph_t { int first; int second; } GERMAN_UMLAUT_DIGRAPHS[];