aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java30
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSet.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java4
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java14
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java25
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java6
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryDictionary.java4
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java22
-rw-r--r--java/src/com/android/inputmethod/latin/define/JniLibName.java6
-rw-r--r--java/src/com/android/inputmethod/latin/define/ProductionFlag.java6
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java206
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java6
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java4
13 files changed, 192 insertions, 153 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 962379016..bc48b85ef 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -278,6 +278,7 @@ public class Keyboard {
}
}
+ // TODO: Remove this method.
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
@@ -616,29 +617,10 @@ public class Keyboard {
mParams = params;
- setTouchPositionCorrectionData(context, params);
-
params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
}
- private static void setTouchPositionCorrectionData(Context context, Params params) {
- final TypedArray a = context.obtainStyledAttributes(
- null, R.styleable.Keyboard, R.attr.keyboardStyle, 0);
- params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0);
- final int resourceId = a.getResourceId(
- R.styleable.Keyboard_touchPositionCorrectionData, 0);
- a.recycle();
- if (resourceId == 0) {
- if (LatinImeLogger.sDBG)
- Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined");
- return;
- }
-
- final String[] data = context.getResources().getStringArray(resourceId);
- params.mTouchPositionCorrection.load(data);
- }
-
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
mParams.mKeysCache = keysCache;
}
@@ -660,6 +642,7 @@ public class Keyboard {
return this;
}
+ // TODO: Remove this method.
public void setTouchPositionCorrectionEnabled(boolean enabled) {
mParams.mTouchPositionCorrection.setEnabled(enabled);
}
@@ -771,6 +754,15 @@ public class Keyboard {
R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
params.mIconsSet.loadIcons(keyboardAttr);
+
+ params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
+ final int resourceId = keyboardAttr.getResourceId(
+ R.styleable.Keyboard_touchPositionCorrectionData, 0);
+ params.mTouchPositionCorrection.setEnabled(resourceId != 0);
+ if (resourceId != 0) {
+ final String[] data = mResources.getStringArray(resourceId);
+ params.mTouchPositionCorrection.load(data);
+ }
} finally {
keyAttr.recycle();
keyboardAttr.recycle();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 52096c843..bb11a9b77 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -63,8 +63,6 @@ public class KeyboardSet {
new HashMap<KeyboardId, SoftReference<Keyboard>>();
private static final KeysCache sKeysCache = new KeysCache();
- private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo();
-
public static class KeyboardSetException extends RuntimeException {
public final KeyboardId mKeyboardId;
public KeyboardSetException(Throwable cause, KeyboardId keyboardId) {
@@ -209,6 +207,8 @@ public class KeyboardSet {
private final Params mParams = new Params();
+ private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo();
+
public Builder(Context context, EditorInfo editorInfo) {
mContext = context;
mPackageName = context.getPackageName();
@@ -229,15 +229,13 @@ public class KeyboardSet {
}
// TODO: Use InputMethodSubtype object as argument.
- public Builder setSubtype(Locale inputLocale, boolean asciiCapable,
- boolean touchPositionCorrectionEnabled) {
+ public Builder setSubtype(Locale inputLocale, boolean asciiCapable) {
final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions(
mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo);
final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
mParams.mEditorInfo.imeOptions)
|| deprecatedForceAscii;
mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale;
- mParams.mTouchPositionCorrectionEnabled = touchPositionCorrectionEnabled;
return this;
}
@@ -255,6 +253,10 @@ public class KeyboardSet {
return this;
}
+ public void setTouchPositionCorrectionEnabled(boolean enabled) {
+ mParams.mTouchPositionCorrectionEnabled = enabled;
+ }
+
public KeyboardSet build() {
if (mParams.mOrientation == Configuration.ORIENTATION_UNDEFINED)
throw new RuntimeException("Screen geometry is not specified");
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 42dd6206c..93d8704de 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -140,9 +140,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions {
builder.setSubtype(
mSubtypeSwitcher.getInputLocale(),
mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
- LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE),
- mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
- LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
+ LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE));
builder.setOptions(
settingsValues.isVoiceKeyEnabled(editorInfo),
settingsValues.isVoiceKeyOnMain(),
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 9909638d4..c43683f2d 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -40,14 +40,13 @@ public class BinaryDictionary extends Dictionary {
public static final int MAX_WORDS = 18;
private static final String TAG = "BinaryDictionary";
- private static final int MAX_PROXIMITY_CHARS_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
private static final int MAX_BIGRAMS = 60;
private static final int TYPED_LETTER_MULTIPLIER = 2;
private int mDicTypeId;
private long mNativeDict;
- private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE];
+ private final int[] mInputCodes = new int[MAX_WORD_LENGTH];
private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
private final int[] mScores = new int[MAX_WORDS];
@@ -111,8 +110,7 @@ public class BinaryDictionary extends Dictionary {
}
private native long openNative(String sourceDir, long dictOffset, long dictSize,
- int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength,
- int maxWords, int maxAlternatives);
+ int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords);
private native void closeNative(long dict);
private native boolean isValidWordNative(long dict, char[] word, int wordLength);
private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates,
@@ -120,7 +118,7 @@ public class BinaryDictionary extends Dictionary {
int[] scores);
private native int getBigramsNative(long dict, char[] prevWord, int prevWordLength,
int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores,
- int maxWordLength, int maxBigrams, int maxAlternatives);
+ int maxWordLength, int maxBigrams);
private static native double calcNormalizedScoreNative(
char[] before, int beforeLength, char[] after, int afterLength, int score);
private static native int editDistanceNative(
@@ -128,8 +126,7 @@ public class BinaryDictionary extends Dictionary {
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_PROXIMITY_CHARS_SIZE);
+ TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS);
}
@Override
@@ -148,8 +145,7 @@ public class BinaryDictionary extends Dictionary {
}
int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize,
- mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS,
- MAX_PROXIMITY_CHARS_SIZE);
+ mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS);
if (count > MAX_BIGRAMS) {
count = MAX_BIGRAMS;
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index f8de029bd..098913bef 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -28,17 +28,12 @@ import java.util.LinkedList;
* be searched for suggestions and valid words.
*/
public class ExpandableDictionary extends Dictionary {
- /**
- * There is difference between what java and native code can handle.
- * It uses 32 because Java stack overflows when greater value is used.
- */
- protected static final int MAX_WORD_LENGTH = 32;
// Bigram frequency is a fixed point number with 1 meaning 1.2 and 255 meaning 1.8.
protected static final int BIGRAM_MAX_FREQUENCY = 255;
private Context mContext;
- private char[] mWordBuilder = new char[MAX_WORD_LENGTH];
+ private char[] mWordBuilder = new char[BinaryDictionary.MAX_WORD_LENGTH];
private int mDicTypeId;
private int mMaxDepth;
private int mInputLength;
@@ -113,7 +108,7 @@ public class ExpandableDictionary extends Dictionary {
public ExpandableDictionary(Context context, int dicTypeId) {
mContext = context;
clearDictionary();
- mCodes = new int[MAX_WORD_LENGTH][];
+ mCodes = new int[BinaryDictionary.MAX_WORD_LENGTH][];
mDicTypeId = dicTypeId;
}
@@ -151,10 +146,13 @@ public class ExpandableDictionary extends Dictionary {
}
public int getMaxWordLength() {
- return MAX_WORD_LENGTH;
+ return BinaryDictionary.MAX_WORD_LENGTH;
}
public void addWord(String word, int frequency) {
+ if (word.length() >= BinaryDictionary.MAX_WORD_LENGTH) {
+ return;
+ }
addWordRec(mRoots, word, 0, frequency, null);
}
@@ -201,6 +199,9 @@ public class ExpandableDictionary extends Dictionary {
// Currently updating contacts, don't return any results.
if (mUpdatingDictionary) return;
}
+ if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) {
+ return;
+ }
getWordsInner(codes, callback, proximityInfo);
}
@@ -488,7 +489,7 @@ public class ExpandableDictionary extends Dictionary {
}
// Local to reverseLookUp, but do not allocate each time.
- private final char[] mLookedUpString = new char[MAX_WORD_LENGTH];
+ private final char[] mLookedUpString = new char[BinaryDictionary.MAX_WORD_LENGTH];
/**
* reverseLookUp retrieves the full word given a list of terminal nodes and adds those words
@@ -502,15 +503,15 @@ public class ExpandableDictionary extends Dictionary {
for (NextWord nextWord : terminalNodes) {
node = nextWord.mWord;
freq = nextWord.getFrequency();
- int index = MAX_WORD_LENGTH;
+ int index = BinaryDictionary.MAX_WORD_LENGTH;
do {
--index;
mLookedUpString[index] = node.mCode;
node = node.mParent;
} while (node != null);
- callback.addWord(mLookedUpString, index, MAX_WORD_LENGTH - index, freq, mDicTypeId,
- Dictionary.BIGRAM);
+ callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index,
+ freq, mDicTypeId, Dictionary.BIGRAM);
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0669ee668..86c153958 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -125,12 +125,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
/**
- * The subtype extra value used to indicate that the subtype keyboard layout supports touch
- * position correction.
- */
- public static final String SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION =
- "SupportTouchPositionCorrection";
- /**
* The subtype extra value used to indicate that the subtype keyboard layout should be loaded
* from the specified locale.
*/
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index db2cdf967..62525c205 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -247,8 +247,8 @@ public class UserHistoryDictionary extends ExpandableDictionary {
// to recursive lookup
if (null == word1) {
super.addWord(word2, frequency);
- } else if (word1.length() < MAX_WORD_LENGTH
- && word2.length() < MAX_WORD_LENGTH) {
+ } else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH
+ && word2.length() < BinaryDictionary.MAX_WORD_LENGTH) {
super.setBigram(word1, word2, frequency);
}
cursor.moveToNext();
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 29a7e4816..555a49ef4 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -104,7 +104,11 @@ public class WordComposer {
return size() > 0;
}
+ // TODO: make sure that the index should not exceed MAX_WORD_LENGTH
public int getCodeAt(int index) {
+ if (index >= BinaryDictionary.MAX_WORD_LENGTH) {
+ return -1;
+ }
return mPrimaryKeyCodes[index];
}
@@ -123,7 +127,6 @@ public class WordComposer {
// TODO: remove input keyDetector
public void add(int primaryCode, int x, int y, KeyDetector keyDetector) {
- final int[] codes;
final int keyX;
final int keyY;
if (null == keyDetector
@@ -131,17 +134,13 @@ public class WordComposer {
|| y == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE
|| x == KeyboardActionListener.NOT_A_TOUCH_COORDINATE
|| y == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) {
- codes = new int[] { primaryCode };
keyX = x;
keyY = y;
} else {
- final Key key = keyDetector.detectHitKey(x, y);
- // TODO: Pass an integer instead of an integer array
- codes = new int[] { key != null ? key.mCode : NOT_A_CODE };
keyX = keyDetector.getTouchX(x);
keyY = keyDetector.getTouchY(y);
}
- add(primaryCode, codes, keyX, keyY);
+ add(primaryCode, keyX, keyY);
}
/**
@@ -149,12 +148,13 @@ public class WordComposer {
* the array containing unicode for adjacent keys, sorted by reducing probability/proximity.
* @param codes the array of unicode values
*/
- private void add(int primaryCode, int[] codes, int keyX, int keyY) {
+ private void add(int primaryCode, int keyX, int keyY) {
final int newIndex = size();
mTypedWord.appendCodePoint(primaryCode);
refreshSize();
- mPrimaryKeyCodes[newIndex] = codes[0];
if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
+ mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE
+ ? Character.toLowerCase(primaryCode) : primaryCode;
mXCoordinates[newIndex] = keyX;
mYCoordinates[newIndex] = keyY;
}
@@ -177,13 +177,11 @@ public class WordComposer {
if (key.mCode == codePoint) {
final int x = key.mX + key.mWidth / 2;
final int y = key.mY + key.mHeight / 2;
- // TODO: Pass an integer instead of an integer array
- add(codePoint, new int[] { key.mCode }, x, y);
+ add(codePoint, x, y);
return;
}
}
- add(codePoint, new int[] { codePoint },
- WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
+ add(codePoint, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/define/JniLibName.java b/java/src/com/android/inputmethod/latin/define/JniLibName.java
index 3e94a3c07..e23e1a968 100644
--- a/java/src/com/android/inputmethod/latin/define/JniLibName.java
+++ b/java/src/com/android/inputmethod/latin/define/JniLibName.java
@@ -16,6 +16,10 @@
package com.android.inputmethod.latin.define;
-public class JniLibName {
+public final class JniLibName {
+ private JniLibName() {
+ // This class is not publicly instantiable.
+ }
+
public static final String JNI_LIB_NAME = "jni_latinime";
}
diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
index cfb1d09cc..de2057669 100644
--- a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
+++ b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
@@ -16,6 +16,10 @@
package com.android.inputmethod.latin.define;
-public class ProductionFlag {
+public final class ProductionFlag {
+ private ProductionFlag() {
+ // This class is not publicly instantiable.
+ }
+
public static final boolean IS_EXPERIMENTAL = false;
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 42dd4df34..af7f863ee 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -47,7 +47,6 @@ public class BinaryDictInputOutput {
* s | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL
* | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS
* | has bigrams ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_BIGRAMS
- * | is shortcut only ? 1 bit, 1 = yes, 0 = no : FLAG_IS_SHORTCUT_ONLY
*
* c | IF FLAG_HAS_MULTIPLE_CHARS
* h | char, char, char, char n * (1 or 3 bytes) : use CharGroupInfo for i/o helpers
@@ -74,7 +73,7 @@ public class BinaryDictInputOutput {
* dress
*
* | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS
- * | shortcut targets address list
+ * | shortcut string list
* | IF FLAG_IS_TERMINAL && FLAG_HAS_BIGRAMS
* | bigrams address list
*
@@ -89,7 +88,7 @@ public class BinaryDictInputOutput {
* the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control
* characters which should never happen anyway (and still work, but take 3 bytes).
*
- * bigram and shortcut address list is:
+ * bigram address list is:
* <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_ATTRIBUTE_HAS_NEXT
* | addressSign = 1 bit, : FLAG_ATTRIBUTE_OFFSET_NEGATIVE
* | 1 = must take -address, 0 = must take +address
@@ -107,8 +106,16 @@ public class BinaryDictInputOutput {
* | read 3 bytes, add top 4 bits
* | END
* | if (FLAG_ATTRIBUTE_OFFSET_NEGATIVE) then address = -address
- * if (FLAG_ATTRIBUTE_HAS_NET) goto bigram_and_shortcut_address_list_is
+ * if (FLAG_ATTRIBUTE_HAS_NEXT) goto bigram_and_shortcut_address_list_is
*
+ * shortcut string list is:
+ * <byte size> = GROUP_SHORTCUT_LIST_SIZE_SIZE bytes, big-endian: size of the list, in bytes.
+ * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_ATTRIBUTE_HAS_NEXT
+ * | reserved = 3 bits, must be 0
+ * | 4 bits : frequency : mask with FLAG_ATTRIBUTE_FREQUENCY
+ * <shortcut> = | string of characters at the char format described above, with the terminator
+ * | used to signal the end of the string.
+ * if (FLAG_ATTRIBUTE_HAS_NEXT goto flags
*/
private static final int VERSION_1_MAGIC_NUMBER = 0x78B1;
@@ -136,7 +143,6 @@ public class BinaryDictInputOutput {
private static final int FLAG_IS_TERMINAL = 0x10;
private static final int FLAG_HAS_SHORTCUT_TARGETS = 0x08;
private static final int FLAG_HAS_BIGRAMS = 0x04;
- private static final int FLAG_IS_SHORTCUT_ONLY = 0x02;
private static final int FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
private static final int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
@@ -154,6 +160,7 @@ public class BinaryDictInputOutput {
private static final int GROUP_MAX_ADDRESS_SIZE = 3;
private static final int GROUP_ATTRIBUTE_FLAGS_SIZE = 1;
private static final int GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE = 3;
+ private static final int GROUP_SHORTCUT_LIST_SIZE_SIZE = 2;
private static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE;
private static final int INVALID_CHARACTER = -1;
@@ -215,25 +222,66 @@ public class BinaryDictInputOutput {
/**
* Writes a char array to a byte buffer.
*
- * @param characters the character array to write.
+ * @param codePoints the code point array to write.
* @param buffer the byte buffer to write to.
* @param index the index in buffer to write the character array to.
* @return the index after the last character.
*/
- private static int writeCharArray(int[] characters, byte[] buffer, int index) {
- for (int character : characters) {
- if (1 == getCharSize(character)) {
- buffer[index++] = (byte)character;
+ private static int writeCharArray(final int[] codePoints, final byte[] buffer, int index) {
+ for (int codePoint : codePoints) {
+ if (1 == getCharSize(codePoint)) {
+ buffer[index++] = (byte)codePoint;
} else {
- buffer[index++] = (byte)(0xFF & (character >> 16));
- buffer[index++] = (byte)(0xFF & (character >> 8));
- buffer[index++] = (byte)(0xFF & character);
+ buffer[index++] = (byte)(0xFF & (codePoint >> 16));
+ buffer[index++] = (byte)(0xFF & (codePoint >> 8));
+ buffer[index++] = (byte)(0xFF & codePoint);
}
}
return index;
}
/**
+ * Writes a string with our character format to a byte buffer.
+ *
+ * This will also write the terminator byte.
+ *
+ * @param buffer the byte buffer to write to.
+ * @param origin the offset to write from.
+ * @param word the string to write.
+ * @return the size written, in bytes.
+ */
+ private static int writeString(final byte[] buffer, final int origin,
+ final String word) {
+ final int length = word.length();
+ int index = origin;
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ if (1 == getCharSize(codePoint)) {
+ buffer[index++] = (byte)codePoint;
+ } else {
+ buffer[index++] = (byte)(0xFF & (codePoint >> 16));
+ buffer[index++] = (byte)(0xFF & (codePoint >> 8));
+ buffer[index++] = (byte)(0xFF & codePoint);
+ }
+ }
+ buffer[index++] = GROUP_CHARACTERS_TERMINATOR;
+ return index - origin;
+ }
+
+ /**
+ * Reads a string from a RandomAccessFile. This is the converse of the above method.
+ */
+ private static String readString(final RandomAccessFile source) throws IOException {
+ final StringBuilder s = new StringBuilder();
+ int character = readChar(source);
+ while (character != INVALID_CHARACTER) {
+ s.appendCodePoint(character);
+ character = readChar(source);
+ }
+ return s.toString();
+ }
+
+ /**
* Reads a character from the file.
*
* This follows the character format documented earlier in this source file.
@@ -294,6 +342,36 @@ public class BinaryDictInputOutput {
}
/**
+ * Compute the size of a shortcut in bytes.
+ */
+ private static int getShortcutSize(final WeightedString shortcut) {
+ int size = GROUP_ATTRIBUTE_FLAGS_SIZE;
+ final String word = shortcut.mWord;
+ final int length = word.length();
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ size += CharEncoding.getCharSize(codePoint);
+ }
+ size += GROUP_TERMINATOR_SIZE;
+ return size;
+ }
+
+ /**
+ * Compute the size of a shortcut list in bytes.
+ *
+ * This is known in advance and does not change according to position in the file
+ * like address lists do.
+ */
+ private static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) {
+ if (null == shortcutList) return 0;
+ int size = GROUP_SHORTCUT_LIST_SIZE_SIZE;
+ for (final WeightedString shortcut : shortcutList) {
+ size += getShortcutSize(shortcut);
+ }
+ return size;
+ }
+
+ /**
* Compute the maximum size of a CharGroup, assuming 3-byte addresses for everything.
*
* @param group the CharGroup to compute the size of.
@@ -304,10 +382,7 @@ public class BinaryDictInputOutput {
// If terminal, one byte for the frequency
if (group.isTerminal()) size += GROUP_FREQUENCY_SIZE;
size += GROUP_MAX_ADDRESS_SIZE; // For children address
- if (null != group.mShortcutTargets) {
- size += (GROUP_ATTRIBUTE_FLAGS_SIZE + GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE)
- * group.mShortcutTargets.size();
- }
+ size += getShortcutListSize(group.mShortcutTargets);
if (null != group.mBigrams) {
size += (GROUP_ATTRIBUTE_FLAGS_SIZE + GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE)
* group.mBigrams.size();
@@ -339,13 +414,6 @@ public class BinaryDictInputOutput {
}
/**
- * Helper method to find out if a character info is a shortcut only.
- */
- private static boolean isShortcutOnly(final CharGroupInfo info) {
- return 0 != (info.mFlags & FLAG_IS_SHORTCUT_ONLY);
- }
-
- /**
* Compute the size, in bytes, that an address will occupy.
*
* This can be used either for children addresses (which are always positive) or for
@@ -430,15 +498,7 @@ public class BinaryDictInputOutput {
final int offset = group.mChildren.mCachedAddress - offsetBasePoint;
groupSize += getByteSize(offset);
}
- if (null != group.mShortcutTargets) {
- for (WeightedString target : group.mShortcutTargets) {
- final int offsetBasePoint = groupSize + node.mCachedAddress + size
- + GROUP_FLAGS_SIZE;
- final int addressOfTarget = findAddressOfWord(dict, target.mWord);
- final int offset = addressOfTarget - offsetBasePoint;
- groupSize += getByteSize(offset) + GROUP_FLAGS_SIZE;
- }
- }
+ groupSize += getShortcutListSize(group.mShortcutTargets);
if (null != group.mBigrams) {
for (WeightedString bigram : group.mBigrams) {
final int offsetBasePoint = groupSize + node.mCachedAddress + size
@@ -555,7 +615,7 @@ public class BinaryDictInputOutput {
* @param address the address to write.
* @return the size in bytes the address actually took.
*/
- private static int writeVariableAddress(byte[] buffer, int index, int address) {
+ private static int writeVariableAddress(final byte[] buffer, int index, final int address) {
switch (getByteSize(address)) {
case 1:
buffer[index++] = (byte)address;
@@ -610,9 +670,6 @@ public class BinaryDictInputOutput {
}
flags |= FLAG_HAS_BIGRAMS;
}
- if (group.mIsShortcutOnly) {
- flags |= FLAG_IS_SHORTCUT_ONLY;
- }
return flags;
}
@@ -646,6 +703,17 @@ public class BinaryDictInputOutput {
}
/**
+ * Makes the flag value for a shortcut.
+ *
+ * @param more whether there are more attributes after this one.
+ * @param frequency the frequency of the attribute, 0..15
+ * @return the flags
+ */
+ private static final int makeShortcutFlags(final boolean more, final int frequency) {
+ return (more ? FLAG_ATTRIBUTE_HAS_NEXT : 0) + (frequency & FLAG_ATTRIBUTE_FREQUENCY);
+ }
+
+ /**
* Write a node to memory. The node is expected to have its final position cached.
*
* This can be an empty map, but the more is inside the faster the lookups will be. It can
@@ -675,7 +743,8 @@ public class BinaryDictInputOutput {
for (int i = 0; i < groupCount; ++i) {
CharGroup group = node.mData.get(i);
if (index != group.mCachedAddress) throw new RuntimeException("Bug: write index is not "
- + "the same as the cached address of the group");
+ + "the same as the cached address of the group : "
+ + index + " <> " + group.mCachedAddress);
groupAddress += GROUP_FLAGS_SIZE + getGroupCharactersSize(group);
// Sanity checks.
if (group.mFrequency > MAX_TERMINAL_FREQUENCY) {
@@ -700,19 +769,26 @@ public class BinaryDictInputOutput {
// Write shortcuts
if (null != group.mShortcutTargets) {
+ final int indexOfShortcutByteSize = index;
+ index += GROUP_SHORTCUT_LIST_SIZE_SIZE;
+ groupAddress += GROUP_SHORTCUT_LIST_SIZE_SIZE;
final Iterator shortcutIterator = group.mShortcutTargets.iterator();
while (shortcutIterator.hasNext()) {
final WeightedString target = (WeightedString)shortcutIterator.next();
- final int addressOfTarget = findAddressOfWord(dict, target.mWord);
++groupAddress;
- final int offset = addressOfTarget - groupAddress;
- int shortcutFlags = makeAttributeFlags(shortcutIterator.hasNext(), offset,
+ int shortcutFlags = makeShortcutFlags(shortcutIterator.hasNext(),
target.mFrequency);
buffer[index++] = (byte)shortcutFlags;
- final int shortcutShift = writeVariableAddress(buffer, index, Math.abs(offset));
+ final int shortcutShift = CharEncoding.writeString(buffer, index, target.mWord);
index += shortcutShift;
groupAddress += shortcutShift;
}
+ final int shortcutByteSize = index - indexOfShortcutByteSize;
+ if (shortcutByteSize > 0xFFFF) {
+ throw new RuntimeException("Shortcut list too large");
+ }
+ buffer[indexOfShortcutByteSize] = (byte)(shortcutByteSize >> 8);
+ buffer[indexOfShortcutByteSize + 1] = (byte)(shortcutByteSize & 0xFF);
}
// Write bigrams
if (null != group.mBigrams) {
@@ -932,36 +1008,19 @@ public class BinaryDictInputOutput {
childrenAddress = NO_CHILDREN_ADDRESS;
break;
}
- ArrayList<PendingAttribute> shortcutTargets = null;
+ ArrayList<WeightedString> shortcutTargets = null;
if (0 != (flags & FLAG_HAS_SHORTCUT_TARGETS)) {
- shortcutTargets = new ArrayList<PendingAttribute>();
+ final long pointerBefore = source.getFilePointer();
+ shortcutTargets = new ArrayList<WeightedString>();
+ source.readUnsignedShort(); // Skip the size
while (true) {
final int targetFlags = source.readUnsignedByte();
- ++addressPointer;
- final int sign = 0 == (targetFlags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) ? 1 : -1;
- int targetAddress = addressPointer;
- switch (targetFlags & MASK_ATTRIBUTE_ADDRESS_TYPE) {
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- targetAddress += sign * source.readUnsignedByte();
- addressPointer += 1;
- break;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- targetAddress += sign * source.readUnsignedShort();
- addressPointer += 2;
- break;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- final int offset = ((source.readUnsignedByte() << 16)
- + source.readUnsignedShort());
- targetAddress += sign * offset;
- addressPointer += 3;
- break;
- default:
- throw new RuntimeException("Has shortcut targets with no address");
- }
- shortcutTargets.add(new PendingAttribute(targetFlags & FLAG_ATTRIBUTE_FREQUENCY,
- targetAddress));
+ final String word = CharEncoding.readString(source);
+ shortcutTargets.add(new WeightedString(word,
+ targetFlags & FLAG_ATTRIBUTE_FREQUENCY));
if (0 == (targetFlags & FLAG_ATTRIBUTE_HAS_NEXT)) break;
}
+ addressPointer += (source.getFilePointer() - pointerBefore);
}
ArrayList<PendingAttribute> bigrams = null;
if (0 != (flags & FLAG_HAS_BIGRAMS)) {
@@ -1086,14 +1145,7 @@ public class BinaryDictInputOutput {
int groupOffset = nodeOrigin + getGroupCountSize(count);
for (int i = count; i > 0; --i) {
CharGroupInfo info = readCharGroup(source, groupOffset);
- ArrayList<WeightedString> shortcutTargets = null;
- if (null != info.mShortcutTargets) {
- shortcutTargets = new ArrayList<WeightedString>();
- for (PendingAttribute target : info.mShortcutTargets) {
- final String word = getWordAtAddress(source, headerSize, target.mAddress);
- shortcutTargets.add(new WeightedString(word, target.mFrequency));
- }
- }
+ ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets;
ArrayList<WeightedString> bigrams = null;
if (null != info.mBigrams) {
bigrams = new ArrayList<WeightedString>();
@@ -1112,11 +1164,11 @@ public class BinaryDictInputOutput {
}
nodeContents.add(
new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency,
- children, isShortcutOnly(info)));
+ children, false));
} else {
nodeContents.add(
new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency,
- isShortcutOnly(info)));
+ false));
}
groupOffset = info.mEndAddress;
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java b/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java
index 444b11732..ef7dbb251 100644
--- a/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java
+++ b/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin.makedict;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
import java.util.ArrayList;
/**
@@ -29,12 +31,12 @@ public class CharGroupInfo {
public final int[] mCharacters;
public final int mFrequency;
public final int mChildrenAddress;
- public final ArrayList<PendingAttribute> mShortcutTargets;
+ public final ArrayList<WeightedString> mShortcutTargets;
public final ArrayList<PendingAttribute> mBigrams;
public CharGroupInfo(final int originalAddress, final int endAddress, final int flags,
final int[] characters, final int frequency, final int childrenAddress,
- final ArrayList<PendingAttribute> shortcutTargets,
+ final ArrayList<WeightedString> shortcutTargets,
final ArrayList<PendingAttribute> bigrams) {
mOriginalAddress = originalAddress;
mEndAddress = endAddress;
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 64fcd7f1a..d3ffb47ad 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -311,9 +311,6 @@ public class FusionDictionary implements Iterable<Word> {
public void add(final String word, final int frequency,
final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams) {
- if (null != shortcutTargets) {
- addNeutralWords(shortcutTargets);
- }
if (null != bigrams) {
addNeutralWords(bigrams);
}
@@ -350,7 +347,6 @@ public class FusionDictionary implements Iterable<Word> {
if (null == shortcutTargets) {
throw new RuntimeException("Can't add a shortcut without targets");
}
- addNeutralWords(shortcutTargets);
add(getCodePoints(word), frequency, shortcutTargets, null, true /* isShortcutOnly */);
}