aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dictionaries/en_whitelist.xml297
-rw-r--r--java/proguard.flags4
-rw-r--r--java/res/values-hi/strings.xml4
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java59
-rw-r--r--java/src/com/android/inputmethod/latin/AutoCorrection.java11
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java43
-rw-r--r--java/src/com/android/inputmethod/latin/DicTraverseSession.java14
-rw-r--r--java/src/com/android/inputmethod/latin/NativeUtils.java32
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java33
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java2
-rw-r--r--native/jni/Android.mk2
-rw-r--r--native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp4
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp205
-rw-r--r--native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp37
-rw-r--r--native/jni/com_android_inputmethod_latin_DicTraverseSession.h27
-rw-r--r--native/jni/com_android_inputmethod_latin_NativeUtils.cpp38
-rw-r--r--native/jni/jni_common.cpp6
-rw-r--r--native/jni/src/bigram_dictionary.cpp13
-rw-r--r--native/jni/src/binary_format.h7
-rw-r--r--native/jni/src/char_utils.cpp9
-rw-r--r--native/jni/src/correction.cpp14
-rw-r--r--native/jni/src/correction.h1
-rw-r--r--native/jni/src/debug.h7
-rw-r--r--native/jni/src/dic_traverse_wrapper.cpp (renamed from native/jni/com_android_inputmethod_latin_NativeUtils.h)13
-rw-r--r--native/jni/src/dic_traverse_wrapper.h66
-rw-r--r--native/jni/src/dictionary.cpp16
-rw-r--r--native/jni/src/dictionary.h11
-rw-r--r--native/jni/src/geometry_utils.h103
-rw-r--r--native/jni/src/gesture/gesture_decoder_wrapper.h24
-rw-r--r--native/jni/src/gesture/incremental_decoder_interface.h7
-rw-r--r--native/jni/src/gesture/incremental_decoder_wrapper.h24
-rw-r--r--native/jni/src/proximity_info.cpp70
-rw-r--r--native/jni/src/proximity_info.h18
-rw-r--r--native/jni/src/proximity_info_state.h30
-rw-r--r--native/jni/src/terminal_attributes.h3
-rw-r--r--native/jni/src/unigram_dictionary.cpp37
-rw-r--r--native/jni/src/words_priority_queue.h26
-rw-r--r--tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java4
-rw-r--r--tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java49
42 files changed, 942 insertions, 461 deletions
diff --git a/dictionaries/en_whitelist.xml b/dictionaries/en_whitelist.xml
new file mode 100644
index 000000000..e11935fdf
--- /dev/null
+++ b/dictionaries/en_whitelist.xml
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<shortcuts>
+ <entry shortcut="ill">
+ <target replacement="I'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="acomodate">
+ <target replacement="accommodate" priority="whitelist" />
+ </entry>
+ <entry shortcut="aint">
+ <target replacement="ain't" priority="whitelist" />
+ </entry>
+ <entry shortcut="alot">
+ <target replacement="a lot" priority="whitelist" />
+ </entry>
+ <entry shortcut="andteh">
+ <target replacement="and the" priority="whitelist" />
+ </entry>
+ <entry shortcut="arent">
+ <target replacement="aren't" priority="whitelist" />
+ </entry>
+ <entry shortcut="bern">
+ <target replacement="been" priority="whitelist" />
+ </entry>
+ <entry shortcut="bot">
+ <target replacement="not" priority="whitelist" />
+ </entry>
+ <entry shortcut="bur">
+ <target replacement="but" priority="whitelist" />
+ </entry>
+ <entry shortcut="cam">
+ <target replacement="can" priority="whitelist" />
+ </entry>
+ <entry shortcut="cant">
+ <target replacement="can't" priority="whitelist" />
+ </entry>
+ <entry shortcut="dame">
+ <target replacement="same" priority="whitelist" />
+ </entry>
+ <entry shortcut="didint">
+ <target replacement="didn't" priority="whitelist" />
+ </entry>
+ <entry shortcut="dormer">
+ <target replacement="former" priority="whitelist" />
+ </entry>
+ <entry shortcut="dud">
+ <target replacement="did" priority="whitelist" />
+ </entry>
+ <entry shortcut="fay">
+ <target replacement="day" priority="whitelist" />
+ </entry>
+ <entry shortcut="fife">
+ <target replacement="five" priority="whitelist" />
+ </entry>
+ <entry shortcut="foo">
+ <target replacement="for" priority="whitelist" />
+ </entry>
+ <entry shortcut="fora">
+ <target replacement="for a" priority="whitelist" />
+ </entry>
+ <entry shortcut="galled">
+ <target replacement="called" priority="whitelist" />
+ </entry>
+ <entry shortcut="goo">
+ <target replacement="too" priority="whitelist" />
+ </entry>
+ <entry shortcut="hed">
+ <target replacement="he'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="hel">
+ <target replacement="he'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="heres">
+ <target replacement="here's" priority="whitelist" />
+ </entry>
+ <entry shortcut="hew">
+ <target replacement="new" priority="whitelist" />
+ </entry>
+ <entry shortcut="hoe">
+ <target replacement="how" priority="whitelist" />
+ </entry>
+ <entry shortcut="hoes">
+ <target replacement="how's" priority="whitelist" />
+ </entry>
+ <entry shortcut="howd">
+ <target replacement="how'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="howll">
+ <target replacement="how'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="hows">
+ <target replacement="how's" priority="whitelist" />
+ </entry>
+ <entry shortcut="howve">
+ <target replacement="how've" priority="whitelist" />
+ </entry>
+ <entry shortcut="hum">
+ <target replacement="him" priority="whitelist" />
+ </entry>
+ <entry shortcut="i">
+ <target replacement="I" priority="whitelist" />
+ </entry>
+ <entry shortcut="ifs">
+ <target replacement="its" priority="whitelist" />
+ </entry>
+ <entry shortcut="il">
+ <target replacement="I'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="im">
+ <target replacement="I'm" priority="whitelist" />
+ </entry>
+ <entry shortcut="inteh">
+ <target replacement="in the" priority="whitelist" />
+ </entry>
+ <entry shortcut="itd">
+ <target replacement="it'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="itsa">
+ <target replacement="it's a" priority="whitelist" />
+ </entry>
+ <entry shortcut="lets">
+ <target replacement="let's" priority="whitelist" />
+ </entry>
+ <entry shortcut="maam">
+ <target replacement="ma'am" priority="whitelist" />
+ </entry>
+ <entry shortcut="manu">
+ <target replacement="many" priority="whitelist" />
+ </entry>
+ <entry shortcut="mare">
+ <target replacement="made" priority="whitelist" />
+ </entry>
+ <entry shortcut="mew">
+ <target replacement="new" priority="whitelist" />
+ </entry>
+ <entry shortcut="mire">
+ <target replacement="more" priority="whitelist" />
+ </entry>
+ <entry shortcut="moat">
+ <target replacement="most" priority="whitelist" />
+ </entry>
+ <entry shortcut="mot">
+ <target replacement="not" priority="whitelist" />
+ </entry>
+ <entry shortcut="mote">
+ <target replacement="note" priority="whitelist" />
+ </entry>
+ <entry shortcut="motes">
+ <target replacement="notes" priority="whitelist" />
+ </entry>
+ <entry shortcut="mow">
+ <target replacement="now" priority="whitelist" />
+ </entry>
+ <entry shortcut="namer">
+ <target replacement="named" priority="whitelist" />
+ </entry>
+ <entry shortcut="nave">
+ <target replacement="have" priority="whitelist" />
+ </entry>
+ <entry shortcut="nee">
+ <target replacement="new" priority="whitelist" />
+ </entry>
+ <entry shortcut="nigh">
+ <target replacement="high" priority="whitelist" />
+ </entry>
+ <entry shortcut="nit">
+ <target replacement="not" priority="whitelist" />
+ </entry>
+ <entry shortcut="oft">
+ <target replacement="off" priority="whitelist" />
+ </entry>
+ <entry shortcut="os">
+ <target replacement="is" priority="whitelist" />
+ </entry>
+ <entry shortcut="pater">
+ <target replacement="later" priority="whitelist" />
+ </entry>
+ <entry shortcut="rook">
+ <target replacement="took" priority="whitelist" />
+ </entry>
+ <entry shortcut="shel">
+ <target replacement="she'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="shouldent">
+ <target replacement="shouldn't" priority="whitelist" />
+ </entry>
+ <entry shortcut="sill">
+ <target replacement="will" priority="whitelist" />
+ </entry>
+ <entry shortcut="sown">
+ <target replacement="down" priority="whitelist" />
+ </entry>
+ <entry shortcut="thatd">
+ <target replacement="that'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="tine">
+ <target replacement="time" priority="whitelist" />
+ </entry>
+ <entry shortcut="thong">
+ <target replacement="thing" priority="whitelist" />
+ </entry>
+ <entry shortcut="tome">
+ <target replacement="time" priority="whitelist" />
+ </entry>
+ <entry shortcut="uf">
+ <target replacement="if" priority="whitelist" />
+ </entry>
+ <entry shortcut="un">
+ <target replacement="in" priority="whitelist" />
+ </entry>
+ <entry shortcut="UnitedStates">
+ <target replacement="United States" priority="whitelist" />
+ </entry>
+ <entry shortcut="unitedstates">
+ <target replacement="United States" priority="whitelist" />
+ </entry>
+ <entry shortcut="visavis">
+ <target replacement="vis-a-vis" priority="whitelist" />
+ </entry>
+ <entry shortcut="wierd">
+ <target replacement="weird" priority="whitelist" />
+ </entry>
+ <entry shortcut="wel">
+ <target replacement="we'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="wer">
+ <target replacement="we're" priority="whitelist" />
+ </entry>
+ <entry shortcut="whatd">
+ <target replacement="what'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="whatm">
+ <target replacement="what'm" priority="whitelist" />
+ </entry>
+ <entry shortcut="whatre">
+ <target replacement="what're" priority="whitelist" />
+ </entry>
+ <entry shortcut="whats">
+ <target replacement="what's" priority="whitelist" />
+ </entry>
+ <entry shortcut="whens">
+ <target replacement="when's" priority="whitelist" />
+ </entry>
+ <entry shortcut="whered">
+ <target replacement="where'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="wherell">
+ <target replacement="where'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="wheres">
+ <target replacement="where's" priority="whitelist" />
+ </entry>
+ <entry shortcut="wholl">
+ <target replacement="who'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="whove">
+ <target replacement="who've" priority="whitelist" />
+ </entry>
+ <entry shortcut="whyd">
+ <target replacement="why'd" priority="whitelist" />
+ </entry>
+ <entry shortcut="whyll">
+ <target replacement="why'll" priority="whitelist" />
+ </entry>
+ <entry shortcut="whys">
+ <target replacement="why's" priority="whitelist" />
+ </entry>
+ <entry shortcut="whyve">
+ <target replacement="why've" priority="whitelist" />
+ </entry>
+ <entry shortcut="wont">
+ <target replacement="won't" priority="whitelist" />
+ </entry>
+ <entry shortcut="yall">
+ <target replacement="y'all" priority="whitelist" />
+ </entry>
+ <entry shortcut="youd">
+ <target replacement="you'd" priority="whitelist" />
+ </entry>
+</shortcuts>
diff --git a/java/proguard.flags b/java/proguard.flags
index 24b4c1987..ac5b7df16 100644
--- a/java/proguard.flags
+++ b/java/proguard.flags
@@ -44,6 +44,10 @@
<init>(...);
}
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
-keep class com.android.inputmethod.research.ResearchLogger {
void flush();
void publishCurrentLogUnit(...);
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 254c2d29b..56642c478 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -46,9 +46,9 @@
<string name="configure_dictionaries_title" msgid="4238652338556902049">"एड-ऑन डिक्शनरी"</string>
<string name="main_dictionary" msgid="4798763781818361168">"मुख्‍य डिक्‍शनरी"</string>
<string name="prefs_show_suggestions" msgid="8026799663445531637">"सुधार सुझाव दिखाएं"</string>
- <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"लिखते समय सुझाए गए शब्‍द प्रदर्शित करें"</string>
+ <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"लिखते समय सुझाए गए शब्‍द दिखाएं"</string>
<string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"हमेशा दिखाएं"</string>
- <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"र्पोट्रेट मोड पर प्रदर्शित करें"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"र्पोट्रेट मोड पर दिखाएं"</string>
<string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"हमेशा छुपाएं"</string>
<string name="auto_correction" msgid="4979925752001319458">"स्‍वत: सुधार"</string>
<string name="auto_correction_summary" msgid="5625751551134658006">"Spacebar और विराम चिह्न गलत लिखे गए शब्‍दों को स्‍वचालित रूप से ठीक करते हैं"</string>
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 4088f3e93..9590290ea 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -835,20 +835,6 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
return false;
}
- @Override
- public void draw(Canvas c) {
- Utils.GCUtils.getInstance().reset();
- boolean tryGC = true;
- for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
- try {
- super.draw(c);
- tryGC = false;
- } catch (OutOfMemoryError e) {
- tryGC = Utils.GCUtils.getInstance().tryGCOrWait(TAG, e);
- }
- }
- }
-
/**
* Receives hover events from the input framework.
*
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 85360c410..7d565a64f 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -29,7 +29,6 @@ import com.android.inputmethod.keyboard.internal.GestureStroke;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;
@@ -130,10 +129,6 @@ public class PointerTracker implements PointerTrackerQueue.Element {
private static final InputPointers sAggregratedPointers = new InputPointers(
GestureStroke.DEFAULT_CAPACITY);
private static PointerTrackerQueue sPointerTrackerQueue;
- // HACK: Change gesture detection criteria depending on this variable.
- // TODO: Find more comprehensive ways to detect a gesture start.
- // True when the previous user input was a gesture input, not a typing input.
- private static boolean sWasInGesture;
public final int mPointerId;
@@ -413,8 +408,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
mKeyDetector = keyDetector;
mKeyboard = keyDetector.getKeyboard();
mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
- mGestureStroke.setGestureSampleLength(
- mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
+ mGestureStroke.setGestureSampleLength(mKeyboard.mMostCommonKeyWidth);
final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
if (newKey != mCurrentKey) {
if (mDrawingProxy != null) {
@@ -526,7 +520,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
public void drawGestureTrail(Canvas canvas, Paint paint) {
if (mInGesture) {
- mGestureStroke.drawGestureTrail(canvas, paint, mLastX, mLastY);
+ mGestureStroke.drawGestureTrail(canvas, paint);
}
}
@@ -586,7 +580,6 @@ public class PointerTracker implements PointerTrackerQueue.Element {
mListener.onEndBatchInput(batchPoints);
clearBatchInputRecognitionStateOfThisPointerTracker();
clearBatchInputPointsOfAllPointerTrackers();
- sWasInGesture = true;
}
private void abortBatchInput() {
@@ -719,7 +712,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
if (sShouldHandleGesture && mIsPossibleGesture) {
final GestureStroke stroke = mGestureStroke;
stroke.addPoint(x, y, gestureTime, isHistorical);
- if (!mInGesture && stroke.isStartOfAGesture(gestureTime, sWasInGesture)) {
+ if (!mInGesture && stroke.isStartOfAGesture()) {
startBatchInput();
}
}
@@ -1002,7 +995,6 @@ public class PointerTracker implements PointerTrackerQueue.Element {
int code = key.mCode;
callListenerOnCodeInput(key, code, x, y);
callListenerOnRelease(key, code, false);
- sWasInGesture = false;
}
private void printTouchEvent(String title, int x, int y, long eventTime) {
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index ae123e29a..ac0a56ba3 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect;
import android.text.TextUtils;
-import android.util.FloatMath;
import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
import com.android.inputmethod.latin.JniUtils;
@@ -155,7 +154,9 @@ public class ProximityInfo {
final float radius = touchPositionCorrection.mRadii[row];
sweetSpotCenterXs[i] = hitBox.exactCenterX() + x * hitBoxWidth;
sweetSpotCenterYs[i] = hitBox.exactCenterY() + y * hitBoxHeight;
- sweetSpotRadii[i] = radius * FloatMath.sqrt(
+ // Note that, in recent versions of Android, FloatMath is actually slower than
+ // java.lang.Math due to the way the JIT optimizes java.lang.Math.
+ sweetSpotRadii[i] = radius * (float)Math.sqrt(
hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 28d6c1d07..79e977a40 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.util.FloatMath;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
@@ -38,19 +37,16 @@ public class GestureStroke {
private int mLastPointY;
private int mMinGestureLength;
- private int mMinGestureLengthWhileInGesture;
private int mMinGestureSampleLength;
// TODO: Move some of these to resource.
- private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 1.0f;
- private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH_WHILE_IN_GESTURE = 0.5f;
- private static final int MIN_GESTURE_DURATION = 150; // msec
- private static final int MIN_GESTURE_DURATION_WHILE_IN_GESTURE = 75; // msec
- private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT = 1.0f / 6.0f;
+ private static final float MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH = 0.75f;
+ private static final int MIN_GESTURE_DURATION = 100; // msec
+ private static final float MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH = 1.0f / 6.0f;
private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; // dip/msec
private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float)(Math.PI / 4.0f);
- private static final float DOUBLE_PI = (float)(2 * Math.PI);
+ private static final float DOUBLE_PI = (float)(2.0f * Math.PI);
// Fade based on number of gesture samples, see MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT
private static final int DRAWING_GESTURE_FADE_START = 10;
@@ -61,21 +57,15 @@ public class GestureStroke {
reset();
}
- public void setGestureSampleLength(final int keyWidth, final int keyHeight) {
+ public void setGestureSampleLength(final int keyWidth) {
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
mMinGestureLength = (int)(keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH);
- mMinGestureLengthWhileInGesture = (int)(
- keyWidth * MIN_GESTURE_LENGTH_RATIO_TO_KEY_WIDTH_WHILE_IN_GESTURE);
- mMinGestureSampleLength = (int)(keyHeight * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_HEIGHT);
+ mMinGestureSampleLength = (int)(keyWidth * MIN_GESTURE_SAMPLING_RATIO_TO_KEY_WIDTH);
}
- public boolean isStartOfAGesture(final int downDuration, final boolean wasInGesture) {
- // The tolerance of the time duration and the stroke length to detect the start of a
- // gesture stroke should be eased when the previous input was a gesture input.
- if (wasInGesture) {
- return downDuration > MIN_GESTURE_DURATION_WHILE_IN_GESTURE
- && mLength > mMinGestureLengthWhileInGesture;
- }
+ public boolean isStartOfAGesture() {
+ final int size = mEventTimes.getLength();
+ final int downDuration = (size > 0) ? mEventTimes.get(size - 1) : 0;
return downDuration > MIN_GESTURE_DURATION && mLength > mMinGestureLength;
}
@@ -154,19 +144,21 @@ public class GestureStroke {
mLastIncrementalBatchSize = size;
}
- private static float getDistance(final int p1x, final int p1y,
- final int p2x, final int p2y) {
- final float dx = p1x - p2x;
- final float dy = p1y - p2y;
- // TODO: Optimize out this {@link FloatMath#sqrt(float)} call.
- return FloatMath.sqrt(dx * dx + dy * dy);
+ private static float getDistance(final int x1, final int y1, final int x2, final int y2) {
+ final float dx = x1 - x2;
+ final float dy = y1 - y2;
+ // Note that, in recent versions of Android, FloatMath is actually slower than
+ // java.lang.Math due to the way the JIT optimizes java.lang.Math.
+ return (float)Math.sqrt(dx * dx + dy * dy);
}
- private static float getAngle(final int p1x, final int p1y, final int p2x, final int p2y) {
- final int dx = p1x - p2x;
- final int dy = p1y - p2y;
+ private static float getAngle(final int x1, final int y1, final int x2, final int y2) {
+ final int dx = x1 - x2;
+ final int dy = y1 - y2;
if (dx == 0 && dy == 0) return 0;
- return (float)Math.atan2(dy, dx);
+ // Would it be faster to call atan2f() directly via JNI? Not sure about what the JIT
+ // does with Math.atan2().
+ return (float)Math.atan2((double)dy, (double)dx);
}
private static float getAngleDiff(final float a1, final float a2) {
@@ -177,12 +169,12 @@ public class GestureStroke {
return diff;
}
- public void drawGestureTrail(Canvas canvas, Paint paint, int lastX, int lastY) {
+ public void drawGestureTrail(final Canvas canvas, final Paint paint) {
// TODO: These paint parameter interpolation should be tunable, possibly introduce an object
// that implements an interface such as Paint getPaint(int step, int strokePoints)
final int size = mXCoordinates.getLength();
- int[] xCoords = mXCoordinates.getPrimitiveArray();
- int[] yCoords = mYCoordinates.getPrimitiveArray();
+ final int[] xCoords = mXCoordinates.getPrimitiveArray();
+ final int[] yCoords = mYCoordinates.getPrimitiveArray();
int alpha = Constants.Color.ALPHA_OPAQUE;
for (int i = size - 1; i > 0 && alpha > 0; i--) {
paint.setAlpha(alpha);
@@ -190,9 +182,6 @@ public class GestureStroke {
alpha -= DRAWING_GESTURE_FADE_RATE;
}
canvas.drawLine(xCoords[i - 1], yCoords[i - 1], xCoords[i], yCoords[i], paint);
- if (i == size - 1) {
- canvas.drawLine(lastX, lastY, xCoords[i], yCoords[i], paint);
- }
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
index a66337404..048166807 100644
--- a/java/src/com/android/inputmethod/latin/AutoCorrection.java
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -75,17 +75,10 @@ public class AutoCorrection {
return maxFreq;
}
- // Returns true if this is a whitelist entry, or it isn't in any dictionary.
- public static boolean isWhitelistedOrNotAWord(
+ // Returns true if this isn't in any dictionary.
+ public static boolean isNotAWord(
final ConcurrentHashMap<String, Dictionary> dictionaries,
final CharSequence word, final boolean ignoreCase) {
- final WhitelistDictionary whitelistDictionary =
- (WhitelistDictionary)dictionaries.get(Dictionary.TYPE_WHITELIST);
- // If "word" is in the whitelist dictionary, it should not be auto corrected.
- if (whitelistDictionary != null
- && whitelistDictionary.shouldForciblyAutoCorrectFrom(word)) {
- return true;
- }
return !isValidWord(dictionaries, word, ignoreCase);
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index e0adc9a71..f0f5cd320 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -51,7 +51,8 @@ public class BinaryDictionary extends Dictionary {
private static final int TYPED_LETTER_MULTIPLIER = 2;
private long mNativeDict;
- private final int[] mInputCodes = new int[MAX_WORD_LENGTH];
+ private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
+ // TODO: The below should be int[] mOutputCodePoints
private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_RESULTS];
private final int[] mSpaceIndices = new int[MAX_SPACES];
private final int[] mOutputScores = new int[MAX_RESULTS];
@@ -78,6 +79,7 @@ public class BinaryDictionary extends Dictionary {
mUseFullEditDistance = useFullEditDistance;
loadDictionary(filename, offset, length);
mDicTraverseSession = new DicTraverseSession(locale);
+ mDicTraverseSession.initSession(mNativeDict);
}
static {
@@ -88,18 +90,17 @@ public class BinaryDictionary extends Dictionary {
int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords,
int maxPredictions);
private native void closeNative(long dict);
- private native int getFrequencyNative(long dict, int[] word, int wordLength);
+ private native int getFrequencyNative(long dict, int[] word);
private native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
private native int getSuggestionsNative(long dict, long proximityInfo, long traverseSession,
int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds,
- int[] inputCodes, int codesSize, int commitPoint, boolean isGesture,
+ int[] inputCodePoints, int codesSize, int commitPoint, boolean isGesture,
int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars,
int[] outputScores, int[] outputIndices, int[] outputTypes);
- private static native float calcNormalizedScoreNative(
- char[] before, int beforeLength, char[] after, int afterLength, int score);
- private static native int editDistanceNative(
- char[] before, int beforeLength, char[] after, int afterLength);
+ private static native float calcNormalizedScoreNative(char[] before, char[] after, int score);
+ private static native int editDistanceNative(char[] before, char[] after);
+ // TODO: Move native dict into session
private final void loadDictionary(String path, long startOffset, long length) {
mNativeDict = openNative(path, startOffset, length, TYPED_LETTER_MULTIPLIER,
FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS, MAX_PREDICTIONS);
@@ -109,9 +110,7 @@ public class BinaryDictionary extends Dictionary {
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final CharSequence prevWord, final ProximityInfo proximityInfo) {
if (!isValidDictionary()) return null;
- Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE);
- Arrays.fill(mOutputChars, (char) 0);
- Arrays.fill(mOutputScores, 0);
+ Arrays.fill(mInputCodePoints, WordComposer.NOT_A_CODE);
// TODO: toLowerCase in the native code
final int[] prevWordCodePointArray = (null == prevWord)
? null : StringUtils.toCodePointArray(prevWord.toString());
@@ -121,7 +120,7 @@ public class BinaryDictionary extends Dictionary {
if (composerSize <= 1 || !isGesture) {
if (composerSize > MAX_WORD_LENGTH - 1) return null;
for (int i = 0; i < composerSize; i++) {
- mInputCodes[i] = composer.getCodeAt(i);
+ mInputCodePoints[i] = composer.getCodeAt(i);
}
}
@@ -129,10 +128,9 @@ public class BinaryDictionary extends Dictionary {
final int codesSize = isGesture ? ips.getPointerSize() : composerSize;
// proximityInfo and/or prevWordForBigrams may not be null.
final int tmpCount = getSuggestionsNative(mNativeDict,
- proximityInfo.getNativeProximityInfo(),
- mDicTraverseSession.getSession(), ips.getXCoordinates(),
- ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(),
- mInputCodes, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
+ proximityInfo.getNativeProximityInfo(), mDicTraverseSession.getSession(),
+ ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(),
+ mInputCodePoints, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices, mOutputTypes);
final int count = Math.min(tmpCount, MAX_PREDICTIONS);
@@ -145,9 +143,10 @@ public class BinaryDictionary extends Dictionary {
++len;
}
if (len > 0) {
+ final int score = SuggestedWordInfo.KIND_WHITELIST == mOutputTypes[j]
+ ? SuggestedWordInfo.MAX_SCORE : mOutputScores[j];
suggestions.add(new SuggestedWordInfo(
- new String(mOutputChars, start, len),
- mOutputScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType));
+ new String(mOutputChars, start, len), score, mOutputTypes[j], mDictType));
}
}
return suggestions;
@@ -158,13 +157,11 @@ public class BinaryDictionary extends Dictionary {
}
public static float calcNormalizedScore(String before, String after, int score) {
- return calcNormalizedScoreNative(before.toCharArray(), before.length(),
- after.toCharArray(), after.length(), score);
+ return calcNormalizedScoreNative(before.toCharArray(), after.toCharArray(), score);
}
public static int editDistance(String before, String after) {
- return editDistanceNative(
- before.toCharArray(), before.length(), after.toCharArray(), after.length());
+ return editDistanceNative(before.toCharArray(), after.toCharArray());
}
@Override
@@ -175,8 +172,8 @@ public class BinaryDictionary extends Dictionary {
@Override
public int getFrequency(CharSequence word) {
if (word == null) return -1;
- int[] chars = StringUtils.toCodePointArray(word.toString());
- return getFrequencyNative(mNativeDict, chars, chars.length);
+ int[] codePoints = StringUtils.toCodePointArray(word.toString());
+ return getFrequencyNative(mNativeDict, codePoints);
}
// TODO: Add a batch process version (isValidBigramMultiple?) to avoid excessive numbers of jni
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index 437876e05..c76815363 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -23,8 +23,8 @@ public class DicTraverseSession {
JniUtils.loadNativeLibrary();
}
private native long setDicTraverseSessionNative(String locale);
- private native void initDicTraverseSessionNative(
- long nativeDicTraverseSession, int[] previousWord, int previwousWordLength);
+ private native void initDicTraverseSessionNative(long nativeDicTraverseSession,
+ long dictionary, int[] previousWord, int previousWordLength);
private native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
private long mNativeDicTraverseSession;
@@ -32,19 +32,19 @@ public class DicTraverseSession {
public DicTraverseSession(Locale locale) {
mNativeDicTraverseSession = createNativeDicTraverseSession(
locale != null ? locale.toString() : "");
- initSession();
}
public long getSession() {
return mNativeDicTraverseSession;
}
- public void initSession() {
- initSession(null, 0);
+ public void initSession(long dictionary) {
+ initSession(dictionary, null, 0);
}
- public void initSession(int[] previousWord, int previousWordLength) {
- initDicTraverseSessionNative(mNativeDicTraverseSession, previousWord, previousWordLength);
+ public void initSession(long dictionary, int[] previousWord, int previousWordLength) {
+ initDicTraverseSessionNative(
+ mNativeDicTraverseSession, dictionary, previousWord, previousWordLength);
}
private final long createNativeDicTraverseSession(String locale) {
diff --git a/java/src/com/android/inputmethod/latin/NativeUtils.java b/java/src/com/android/inputmethod/latin/NativeUtils.java
deleted file mode 100644
index 9cc2bc02e..000000000
--- a/java/src/com/android/inputmethod/latin/NativeUtils.java
+++ /dev/null
@@ -1,32 +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.
- */
-
-package com.android.inputmethod.latin;
-
-public class NativeUtils {
- static {
- JniUtils.loadNativeLibrary();
- }
-
- private NativeUtils() {
- // This utility class is not publicly instantiable.
- }
-
- /**
- * This method just calls up libm's powf() directly.
- */
- public static native float powf(float x, float y);
-}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index a65d36adb..8a2341d5e 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -208,23 +208,34 @@ public class Suggest {
wordComposerForLookup, prevWordForBigram, proximityInfo));
}
- // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
- // but still autocorrected from - in the case the whitelist only capitalizes the word.
- // The whitelist should be case-insensitive, so it's not possible to be consistent with
- // a boolean flag. Right now this is handled with a slight hack in
- // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
- final boolean allowsToBeAutoCorrected = AutoCorrection.isWhitelistedOrNotAWord(
- mDictionaries, consideredWord, wordComposer.isFirstCharCapitalized());
-
- final CharSequence whitelistedWord =
+ final CharSequence whitelistedWordFromWhitelistDictionary =
mWhiteListDictionary.getWhitelistedWord(consideredWord);
- if (whitelistedWord != null) {
+ if (whitelistedWordFromWhitelistDictionary != null) {
// MAX_SCORE ensures this will be considered strong enough to be auto-corrected
- suggestionsSet.add(new SuggestedWordInfo(whitelistedWord,
+ suggestionsSet.add(new SuggestedWordInfo(whitelistedWordFromWhitelistDictionary,
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST,
Dictionary.TYPE_WHITELIST));
}
+ final CharSequence whitelistedWord;
+ if (suggestionsSet.isEmpty()) {
+ whitelistedWord = null;
+ } else if (SuggestedWordInfo.KIND_WHITELIST != suggestionsSet.first().mKind) {
+ whitelistedWord = null;
+ } else {
+ whitelistedWord = suggestionsSet.first().mWord;
+ }
+
+ // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
+ // but still autocorrected from - in the case the whitelist only capitalizes the word.
+ // The whitelist should be case-insensitive, so it's not possible to be consistent with
+ // a boolean flag. Right now this is handled with a slight hack in
+ // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
+ final boolean allowsToBeAutoCorrected = (null != whitelistedWord
+ && !whitelistedWord.equals(consideredWord))
+ || AutoCorrection.isNotAWord(mDictionaries, consideredWord,
+ wordComposer.isFirstCharCapitalized());
+
final boolean hasAutoCorrection;
// TODO: using isCorrectionEnabled here is not very good. It's probably useless, because
// any attempt to do auto-correction is already shielded with a test for this flag; at the
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java
index 1de95d7b8..5a2fdf48e 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java
@@ -212,7 +212,7 @@ public class UserHistoryForgettingCurveUtils {
for (int j = 0; j < ELAPSED_TIME_MAX; ++j) {
final float elapsedHours = j * ELAPSED_TIME_INTERVAL_HOURS;
final float freq = initialFreq
- * NativeUtils.powf(initialFreq, elapsedHours / HALF_LIFE_HOURS);
+ * (float)Math.pow(initialFreq, elapsedHours / HALF_LIFE_HOURS);
final int intFreq = Math.min(FC_FREQ_MAX, Math.max(0, (int)freq));
SCORE_TABLE[i][j] = intFreq;
}
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];
}
}
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java
index 9ebd3bbdd..25e1740cb 100644
--- a/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -112,7 +112,7 @@ public class DictionaryMaker {
public static String getHelp() {
return "Usage: makedict "
- + "[-s <unigrams.xml> [-b <bigrams.xml>] [-c <shortcuts.xml>] "
+ + "[-s <unigrams.xml> [-b <bigrams.xml>] [-c <shortcuts_and_whitelist.xml>] "
+ "| -s <binary input>] [-d <binary output format version 2>] "
+ "[-d1 <binary output format version 1>] [-x <xml output>] [-2]\n"
+ "\n"
@@ -246,7 +246,7 @@ public class DictionaryMaker {
* Read a dictionary from a unigram XML file, and optionally a bigram XML file.
*
* @param unigramXmlFilename the name of the unigram XML file. May not be null.
- * @param shortcutXmlFilename the name of the shortcut XML file, or null if there is none.
+ * @param shortcutXmlFilename the name of the shortcut/whitelist XML file, or null if none.
* @param bigramXmlFilename the name of the bigram XML file. Pass null if there are no bigrams.
* @return the read dictionary.
* @throws FileNotFoundException if one of the files can't be found
diff --git a/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
index 8e2e73505..9ce8c4934 100644
--- a/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
+++ b/tools/dicttool/src/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
@@ -90,6 +90,10 @@ public class XmlDictInputOutput {
public FusionDictionary getFinalDictionary() {
final FusionDictionary dict = mDictionary;
+ for (final String shortcutOnly : mShortcutsMap.keySet()) {
+ if (dict.hasWord(shortcutOnly)) continue;
+ dict.add(shortcutOnly, 0, mShortcutsMap.get(shortcutOnly));
+ }
mDictionary = null;
mShortcutsMap.clear();
mWord = "";
@@ -179,7 +183,7 @@ public class XmlDictInputOutput {
mSrc = attrs.getValue(uri, SRC_ATTRIBUTE);
} else if (DST_TAG.equals(localName)) {
String dst = attrs.getValue(uri, DST_ATTRIBUTE);
- int freq = Integer.parseInt(attrs.getValue(uri, DST_FREQ));
+ int freq = getValueFromFreqString(attrs.getValue(uri, DST_FREQ));
WeightedString bigram = new WeightedString(dst, freq / XML_TO_MEMORY_RATIO);
ArrayList<WeightedString> bigramList = mAssocMap.get(mSrc);
if (null == bigramList) bigramList = new ArrayList<WeightedString>();
@@ -188,6 +192,10 @@ public class XmlDictInputOutput {
}
}
+ protected int getValueFromFreqString(final String freqString) {
+ return Integer.parseInt(freqString);
+ }
+
// This may return an empty map, but will never return null.
public HashMap<String, ArrayList<WeightedString>> getAssocMap() {
return mAssocMap;
@@ -216,22 +224,40 @@ public class XmlDictInputOutput {
}
/**
- * SAX handler for a shortcut XML file.
+ * SAX handler for a shortcut & whitelist XML file.
*/
- static private class ShortcutHandler extends AssociativeListHandler {
+ static private class ShortcutAndWhitelistHandler extends AssociativeListHandler {
private final static String ENTRY_TAG = "entry";
private final static String ENTRY_ATTRIBUTE = "shortcut";
private final static String TARGET_TAG = "target";
private final static String REPLACEMENT_ATTRIBUTE = "replacement";
private final static String TARGET_PRIORITY_ATTRIBUTE = "priority";
+ private final static String WHITELIST_MARKER = "whitelist";
+ private final static int WHITELIST_FREQ_VALUE = 15;
+ private final static int MIN_FREQ = 0;
+ private final static int MAX_FREQ = 14;
- public ShortcutHandler() {
+ public ShortcutAndWhitelistHandler() {
super(ENTRY_TAG, ENTRY_ATTRIBUTE, TARGET_TAG, REPLACEMENT_ATTRIBUTE,
TARGET_PRIORITY_ATTRIBUTE);
}
+ @Override
+ protected int getValueFromFreqString(final String freqString) {
+ if (WHITELIST_MARKER.equals(freqString)) {
+ return WHITELIST_FREQ_VALUE;
+ } else {
+ final int intValue = super.getValueFromFreqString(freqString);
+ if (intValue < MIN_FREQ || intValue > MAX_FREQ) {
+ throw new RuntimeException("Shortcut freq out of range. Accepted range is "
+ + MIN_FREQ + ".." + MAX_FREQ);
+ }
+ return intValue;
+ }
+ }
+
// As per getAssocMap(), this never returns null.
- public HashMap<String, ArrayList<WeightedString>> getShortcutMap() {
+ public HashMap<String, ArrayList<WeightedString>> getShortcutAndWhitelistMap() {
return getAssocMap();
}
}
@@ -243,7 +269,7 @@ public class XmlDictInputOutput {
* representation.
*
* @param unigrams the file to read the data from.
- * @param shortcuts the file to read the shortcuts from, or null.
+ * @param shortcuts the file to read the shortcuts & whitelist from, or null.
* @param bigrams the file to read the bigrams from, or null.
* @return the in-memory representation of the dictionary.
*/
@@ -256,11 +282,12 @@ public class XmlDictInputOutput {
final BigramHandler bigramHandler = new BigramHandler();
if (null != bigrams) parser.parse(bigrams, bigramHandler);
- final ShortcutHandler shortcutHandler = new ShortcutHandler();
- if (null != shortcuts) parser.parse(shortcuts, shortcutHandler);
+ final ShortcutAndWhitelistHandler shortcutAndWhitelistHandler =
+ new ShortcutAndWhitelistHandler();
+ if (null != shortcuts) parser.parse(shortcuts, shortcutAndWhitelistHandler);
final UnigramHandler unigramHandler =
- new UnigramHandler(shortcutHandler.getShortcutMap());
+ new UnigramHandler(shortcutAndWhitelistHandler.getShortcutAndWhitelistMap());
parser.parse(unigrams, unigramHandler);
final FusionDictionary dict = unigramHandler.getFinalDictionary();
final HashMap<String, ArrayList<WeightedString>> bigramMap = bigramHandler.getBigramMap();
@@ -280,7 +307,7 @@ public class XmlDictInputOutput {
*
* This method reads data from the parser and creates a new FusionDictionary with it.
* The format parsed by this method is the format used before Ice Cream Sandwich,
- * which has no support for bigrams or shortcuts.
+ * which has no support for bigrams or shortcuts/whitelist.
* It is important to note that this method expects the parser to have already eaten
* the first, all-encompassing tag.
*
@@ -291,7 +318,7 @@ public class XmlDictInputOutput {
/**
* Writes a dictionary to an XML file.
*
- * The output format is the "second" format, which supports bigrams and shortcuts.
+ * The output format is the "second" format, which supports bigrams and shortcuts/whitelist.
*
* @param destination a destination stream to write to.
* @param dict the dictionary to write.