diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index bc9e8cdd4..1fe23a330 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -29,17 +29,18 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.text.InputType; import android.text.TextUtils; +import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; import android.util.Xml; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeysCache; +import com.android.inputmethod.latin.AdditionalSubtype; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.InputTypeUtils; @@ -72,6 +73,8 @@ public final class KeyboardLayoutSet { private static final String TAG_ELEMENT = "Element"; private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_"; + private static final int SPELLCHECKER_DUMMY_KEYBOARD_WIDTH = 480; + private static final int SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT = 800; private final Context mContext; private final Params mParams; @@ -282,8 +285,7 @@ public final class KeyboardLayoutSet { return this; } - @UsedForTesting - public void disableTouchPositionCorrectionDataForTest() { + public void disableTouchPositionCorrectionData() { mParams.mDisableTouchPositionCorrectionDataForTest = true; } @@ -413,4 +415,47 @@ public final class KeyboardLayoutSet { } } } + + public static KeyboardLayoutSet createKeyboardSetForSpellChecker(final Context context, + final String locale, final String layout) { + final InputMethodSubtype subtype = + AdditionalSubtype.createAdditionalSubtype(locale, layout, null); + return createKeyboardSet(context, subtype, SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, + SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT, false); + } + + public static KeyboardLayoutSet createKeyboardSetForTest(final Context context, + final InputMethodSubtype subtype, final int orientation, + final boolean testCasesHaveTouchCoordinates) { + final DisplayMetrics dm = context.getResources().getDisplayMetrics(); + final int width; + final int height; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + width = Math.max(dm.widthPixels, dm.heightPixels); + height = Math.min(dm.widthPixels, dm.heightPixels); + } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { + width = Math.min(dm.widthPixels, dm.heightPixels); + height = Math.max(dm.widthPixels, dm.heightPixels); + } else { + throw new RuntimeException("Orientation should be ORIENTATION_LANDSCAPE or " + + "ORIENTATION_PORTRAIT: orientation=" + orientation); + } + return createKeyboardSet(context, subtype, width, height, testCasesHaveTouchCoordinates); + } + + private static KeyboardLayoutSet createKeyboardSet(final Context context, + final InputMethodSubtype subtype, final int width, final int height, + final boolean testCasesHaveTouchCoordinates) { + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.inputType = InputType.TYPE_CLASS_TEXT; + final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( + context, editorInfo); + builder.setScreenGeometry(width, height); + builder.setSubtype(subtype); + if (!testCasesHaveTouchCoordinates) { + // For spell checker and tests + builder.disableTouchPositionCorrectionData(); + } + return builder.build(); + } } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index b77e378bf..57d3fede4 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -79,23 +79,6 @@ public class ProximityInfo { mNativeProximityInfo = createNativeProximityInfo(touchPositionCorrection); } - /** - * Constructor for subclasses such as - * {@link com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo}. - */ - protected ProximityInfo(final int[] proximityCharsArray, final int gridWidth, - final int gridHeight) { - this("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null); - mNativeProximityInfo = setProximityInfoNative("" /* locale */, - gridWidth /* displayWidth */, gridHeight /* displayHeight */, - gridWidth, gridHeight, 1 /* mostCommonKeyWidth */, - 1 /* mostCommonKeyHeight */, proximityCharsArray, 0 /* keyCount */, - null /*keyXCoordinates */, null /* keyYCoordinates */, - null /* keyWidths */, null /* keyHeights */, null /* keyCharCodes */, - null /* sweetSpotCenterXs */, null /* sweetSpotCenterYs */, - null /* sweetSpotRadii */); - } - private long mNativeProximityInfo; static { JniUtils.loadNativeLibrary(); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 51bd901fb..e078f03f4 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; @@ -211,9 +210,8 @@ public final class WordComposer { } /** - * Internal method to retrieve reasonable proximity info for a character. + * Add a dummy key by retrieving reasonable coordinates */ - @UsedForTesting public void addKeyInfo(final int codePoint, final Keyboard keyboard) { final int x, y; final Key key; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index aa60496ae..13fcaf48a 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -23,7 +23,7 @@ import android.service.textservice.SpellCheckerService; import android.util.Log; import android.view.textservice.SuggestionsInfo; -import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.ContactsBinaryDictionary; @@ -126,6 +126,19 @@ public final class AndroidSpellCheckerService extends SpellCheckerService return script; } + private static String getKeyboardLayoutNameForScript(final int script) { + switch (script) { + case AndroidSpellCheckerService.SCRIPT_LATIN: + return "qwerty"; + case AndroidSpellCheckerService.SCRIPT_CYRILLIC: + return "east_slavic"; + case AndroidSpellCheckerService.SCRIPT_GREEK: + return "greek"; + default: + throw new RuntimeException("Wrong script supplied: " + script); + } + } + @Override public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { if (!PREF_USE_CONTACTS_KEY.equals(key)) return; @@ -385,9 +398,13 @@ public final class AndroidSpellCheckerService extends SpellCheckerService return pool; } - public DictAndProximity createDictAndProximity(final Locale locale) { + public DictAndKeyboard createDictAndKeyboard(final Locale locale) { final int script = getScriptFromLocale(locale); - final ProximityInfo proximityInfo = new SpellCheckerProximityInfo(script); + final String keyboardLayoutName = getKeyboardLayoutNameForScript(script); + final KeyboardLayoutSet keyboardLayoutSet = + KeyboardLayoutSet.createKeyboardSetForSpellChecker(this, locale.toString(), + keyboardLayoutName); + final DictionaryCollection dictionaryCollection = DictionaryFactory.createMainDictionaryFromManager(this, locale, true /* useFullEditDistance */); @@ -412,6 +429,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService mDictionaryCollectionsList.add( new WeakReference(dictionaryCollection)); } - return new DictAndProximity(dictionaryCollection, proximityInfo); + return new DictAndKeyboard(dictionaryCollection, keyboardLayoutSet); } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 61850e42e..16e9fb77e 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -257,7 +257,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } if (shouldFilterOut(inText, mScript)) { - DictAndProximity dictInfo = null; + DictAndKeyboard dictInfo = null; try { dictInfo = mDictionaryPool.pollWithDefaultTimeout(); if (!DictionaryPool.isAValidDictionary(dictInfo)) { @@ -286,7 +286,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { final int capitalizeType = StringUtils.getCapitalizationType(text); boolean isInDict = true; - DictAndProximity dictInfo = null; + DictAndKeyboard dictInfo = null; try { dictInfo = mDictionaryPool.pollWithDefaultTimeout(); if (!DictionaryPool.isAValidDictionary(dictInfo)) { @@ -296,20 +296,13 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { final int length = text.length(); for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { final int codePoint = text.codePointAt(i); - // The getXYForCodePointAndScript method returns (Y << 16) + X - final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript( - codePoint, mScript); - if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) { - composer.add(codePoint, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); - } else { - composer.add(codePoint, xy & 0xFFFF, xy >> 16); - } + composer.addKeyInfo(codePoint, dictInfo.getKeyboard(codePoint)); } // TODO: make a spell checker option to block offensive words or not final ArrayList suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWord, - dictInfo.mProximityInfo, true /* blockOffensiveWords */); + dictInfo.getProximityInfo(), + true /* blockOffensiveWords */); for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord; suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java new file mode 100644 index 000000000..b77f3e2c5 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.spellcheck; + +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; +import com.android.inputmethod.keyboard.ProximityInfo; + +/** + * A container for a Dictionary and a Keyboard. + */ +public final class DictAndKeyboard { + public final Dictionary mDictionary; + private final Keyboard mKeyboard; + private final Keyboard mManualShiftedKeyboard; + + public DictAndKeyboard( + final Dictionary dictionary, final KeyboardLayoutSet keyboardLayoutSet) { + mDictionary = dictionary; + if (keyboardLayoutSet == null) { + mKeyboard = null; + mManualShiftedKeyboard = null; + return; + } + mKeyboard = keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); + mManualShiftedKeyboard = + keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED); + } + + public Keyboard getKeyboard(final int codePoint) { + if (mKeyboard == null) { + return null; + } + return mKeyboard.getKey(codePoint) != null ? mKeyboard : mManualShiftedKeyboard; + } + + public ProximityInfo getProximityInfo() { + return mKeyboard == null ? null : mKeyboard.getProximityInfo(); + } +} diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java deleted file mode 100644 index 017a4f555..000000000 --- a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.spellcheck; - -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.keyboard.ProximityInfo; - -/** - * A simple container for both a Dictionary and a ProximityInfo. - */ -public final class DictAndProximity { - public final Dictionary mDictionary; - public final ProximityInfo mProximityInfo; - public DictAndProximity(final Dictionary dictionary, final ProximityInfo proximityInfo) { - mDictionary = dictionary; - mProximityInfo = proximityInfo; - } -} diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java index 27964b3c6..a20e09ee8 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java @@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit; * the client code, but may help with sloppy clients. */ @SuppressWarnings("serial") -public final class DictionaryPool extends LinkedBlockingQueue { +public final class DictionaryPool extends LinkedBlockingQueue { private final static String TAG = DictionaryPool.class.getSimpleName(); // How many seconds we wait for a dictionary to become available. Past this delay, we give up in // fear some bug caused a deadlock, and reset the whole pool. @@ -47,7 +47,7 @@ public final class DictionaryPool extends LinkedBlockingQueue private int mSize; private volatile boolean mClosed; final static ArrayList noSuggestions = CollectionUtils.newArrayList(); - private final static DictAndProximity dummyDict = new DictAndProximity( + private final static DictAndKeyboard dummyDict = new DictAndKeyboard( new Dictionary(Dictionary.TYPE_MAIN) { @Override public ArrayList getSuggestions(final WordComposer composer, @@ -64,7 +64,7 @@ public final class DictionaryPool extends LinkedBlockingQueue } }, null); - static public boolean isAValidDictionary(final DictAndProximity dictInfo) { + static public boolean isAValidDictionary(final DictAndKeyboard dictInfo) { return null != dictInfo && dummyDict != dictInfo; } @@ -79,32 +79,32 @@ public final class DictionaryPool extends LinkedBlockingQueue } @Override - public DictAndProximity poll(final long timeout, final TimeUnit unit) + public DictAndKeyboard poll(final long timeout, final TimeUnit unit) throws InterruptedException { - final DictAndProximity dict = poll(); + final DictAndKeyboard dict = poll(); if (null != dict) return dict; synchronized(this) { if (mSize >= mMaxSize) { // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT // expires to avoid a deadlock. - final DictAndProximity result = super.poll(timeout, unit); + final DictAndKeyboard result = super.poll(timeout, unit); if (null == result) { Log.e(TAG, "Deadlock detected ! Resetting dictionary pool"); clear(); mSize = 1; - return mService.createDictAndProximity(mLocale); + return mService.createDictAndKeyboard(mLocale); } else { return result; } } else { ++mSize; - return mService.createDictAndProximity(mLocale); + return mService.createDictAndKeyboard(mLocale); } } } // Convenience method - public DictAndProximity pollWithDefaultTimeout() { + public DictAndKeyboard pollWithDefaultTimeout() { try { return poll(TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException e) { @@ -115,7 +115,7 @@ public final class DictionaryPool extends LinkedBlockingQueue public void close() { synchronized(this) { mClosed = true; - for (DictAndProximity dict : this) { + for (DictAndKeyboard dict : this) { dict.mDictionary.close(); } clear(); @@ -123,7 +123,7 @@ public final class DictionaryPool extends LinkedBlockingQueue } @Override - public boolean offer(final DictAndProximity dict) { + public boolean offer(final DictAndKeyboard dict) { if (mClosed) { dict.mDictionary.close(); return super.offer(dummyDict); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java deleted file mode 100644 index 0c480eaba..000000000 --- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.spellcheck; - -import android.util.SparseIntArray; - -import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.Constants; - -public final class SpellCheckerProximityInfo extends ProximityInfo { - public SpellCheckerProximityInfo(final int script) { - super(getProximityForScript(script), PROXIMITY_GRID_WIDTH, PROXIMITY_GRID_HEIGHT); - } - - private static final int NUL = Constants.NOT_A_CODE; - - // This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside - // native code - this value is passed at creation of the binary object and reused - // as the size of the passed array afterwards so they can't be different. - private static final int ROW_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE; - - // The number of keys in a row of the grid used by the spell checker. - private static final int PROXIMITY_GRID_WIDTH = 11; - // The number of rows in the grid used by the spell checker. - private static final int PROXIMITY_GRID_HEIGHT = 3; - - private static final int NOT_AN_INDEX = -1; - public static final int NOT_A_COORDINATE_PAIR = -1; - - // Helper methods - static void buildProximityIndices(final int[] proximity, final int rowSize, - final SparseIntArray indices) { - for (int i = 0; i < proximity.length; i += rowSize) { - if (NUL != proximity[i]) indices.put(proximity[i], i / rowSize); - } - } - - private static final class Latin { - // The proximity here is the union of - // - the proximity for a QWERTY keyboard. - // - the proximity for an AZERTY keyboard. - // - the proximity for a QWERTZ keyboard. - // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other. - // - // The reasoning behind this construction is, almost any alphabetic text we may want - // to spell check has been entered with one of the keyboards above. Also, specifically - // to English, many spelling errors consist of the last vowel of the word being wrong - // because in English vowels tend to merge with each other in pronunciation. - /* - The Qwerty layout this represents looks like the following: - q w e r t y u i o p - a s d f g h j k l - z x c v b n m - */ - static final int[] PROXIMITY = { - // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter, - // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's. - // The number of rows must be exactly PROXIMITY_GRID_HEIGHT. - 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, - 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL, - 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - // Proximity for row 2. See comment above about size. - 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, - 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - // Proximity for row 3. See comment above about size. - 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL, - 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - }; - - // This is a mapping array from the code point to the index in the PROXIMITY array. - // When we check the spelling of a word, we need to pass (x,y) coordinates to the native - // code for each letter of the word. These are most easily computed from the index in the - // PROXIMITY array. Since we'll need to do that very often, the index lookup from the code - // point needs to be as fast as possible, and a map is probably the best way to do this. - // To avoid unnecessary boxing conversion to Integer, here we use SparseIntArray. - static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE); - - static { - buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES); - } - } - - private static final class Cyrillic { - // TODO: The following table is solely based on the keyboard layout. Consult with Russian - // speakers on commonly misspelled words/letters. - /* - The Russian layout this represents looks like the following: - й ц у к е н г ш щ з х - ф ы в а п р о л д ж э - я ч с м и т ь б ю - - This gives us the following table: - 'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'к', 'у', 'в', 'а', 'п', 'е', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'е', 'к', 'а', 'п', 'р', 'н', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'н', 'е', 'п', 'р', 'о', 'г', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'г', 'н', 'р', 'о', 'л', 'ш', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ш', 'г', 'о', 'л', 'д', 'щ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'щ', 'ш', 'л', 'д', 'ж', 'з', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - 'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'а', 'у', 'к', 'е', 'в', 'п', 'ч', 'с', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'п', 'к', 'е', 'н', 'а', 'р', 'с', 'м', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'р', 'е', 'н', 'г', 'п', 'о', 'м', 'и', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'о', 'н', 'г', 'ш', 'р', 'л', 'и', 'т', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'л', 'г', 'ш', 'щ', 'о', 'д', 'т', 'ь', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'д', 'ш', 'щ', 'з', 'л', 'ж', 'ь', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - 'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'м', 'а', 'п', 'р', 'с', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'и', 'п', 'р', 'о', 'м', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'т', 'р', 'о', 'л', 'и', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - Using the following characters: - */ - private static final int CY_SHORT_I = '\u0439'; // й - private static final int CY_TSE = '\u0446'; // ц - private static final int CY_U = '\u0443'; // у - private static final int CY_KA = '\u043A'; // к - private static final int CY_IE = '\u0435'; // е - private static final int CY_EN = '\u043D'; // н - private static final int CY_GHE = '\u0433'; // г - private static final int CY_SHA = '\u0448'; // ш - private static final int CY_SHCHA = '\u0449'; // щ - private static final int CY_ZE = '\u0437'; // з - private static final int CY_HA = '\u0445'; // х - private static final int CY_EF = '\u0444'; // ф - private static final int CY_YERU = '\u044B'; // ы - private static final int CY_VE = '\u0432'; // в - private static final int CY_A = '\u0430'; // а - private static final int CY_PE = '\u043F'; // п - private static final int CY_ER = '\u0440'; // р - private static final int CY_O = '\u043E'; // о - private static final int CY_EL = '\u043B'; // л - private static final int CY_DE = '\u0434'; // д - private static final int CY_ZHE = '\u0436'; // ж - private static final int CY_E = '\u044D'; // э - private static final int CY_YA = '\u044F'; // я - private static final int CY_CHE = '\u0447'; // ч - private static final int CY_ES = '\u0441'; // с - private static final int CY_EM = '\u043C'; // м - private static final int CY_I = '\u0438'; // и - private static final int CY_TE = '\u0442'; // т - private static final int CY_SOFT_SIGN = '\u044C'; // ь - private static final int CY_BE = '\u0431'; // б - private static final int CY_YU = '\u044E'; // ю - static final int[] PROXIMITY = { - // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter, - // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's. - // The number of rows must be exactly PROXIMITY_GRID_HEIGHT. - CY_SHORT_I, CY_TSE, CY_EF, CY_YERU, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_TSE, CY_SHORT_I, CY_EF, CY_YERU, CY_VE, CY_U, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_U, CY_TSE, CY_YERU, CY_VE, CY_A, CY_KA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_KA, CY_U, CY_VE, CY_A, CY_PE, CY_IE, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_IE, CY_KA, CY_A, CY_PE, CY_ER, CY_EN, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_EN, CY_IE, CY_PE, CY_ER, CY_O, CY_GHE, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_GHE, CY_EN, CY_ER, CY_O, CY_EL, CY_SHA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_SHA, CY_GHE, CY_O, CY_EL, CY_DE, CY_SHCHA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_SHCHA, CY_SHA, CY_EL, CY_DE, CY_ZHE, CY_ZE, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_ZE, CY_SHCHA, CY_DE, CY_ZHE, CY_E, CY_HA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_HA, CY_ZE, CY_ZHE, CY_E, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - // Proximity for row 2. See comment above about size. - CY_EF, CY_SHORT_I, CY_TSE, CY_YERU, CY_YA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_YERU, CY_SHORT_I, CY_TSE, CY_U, CY_EF, CY_VE, CY_YA, CY_CHE, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_VE, CY_TSE, CY_U, CY_KA, CY_YERU, CY_A, CY_YA, CY_CHE, - CY_ES, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_A, CY_U, CY_KA, CY_IE, CY_VE, CY_PE, CY_CHE, CY_ES, - CY_EM, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_PE, CY_KA, CY_IE, CY_EN, CY_A, CY_ER, CY_ES, CY_EM, - CY_I, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_ER, CY_IE, CY_EN, CY_GHE, CY_PE, CY_O, CY_EM, CY_I, - CY_TE, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_O, CY_EN, CY_GHE, CY_SHA, CY_ER, CY_EL, CY_I, CY_TE, - CY_SOFT_SIGN, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_EL, CY_GHE, CY_SHA, CY_SHCHA, CY_O, CY_DE, CY_TE, CY_SOFT_SIGN, - CY_BE, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_DE, CY_SHA, CY_SHCHA, CY_ZE, CY_EL, CY_ZHE, CY_SOFT_SIGN, CY_BE, - CY_YU, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_ZHE, CY_SHCHA, CY_ZE, CY_HA, CY_DE, CY_E, CY_BE, CY_YU, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_E, CY_ZE, CY_HA, CY_YU, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - // Proximity for row 3. See comment above about size. - CY_YA, CY_EF, CY_YERU, CY_VE, CY_CHE, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_CHE, CY_YERU, CY_VE, CY_A, CY_YA, CY_ES, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_ES, CY_VE, CY_A, CY_PE, CY_CHE, CY_EM, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_EM, CY_A, CY_PE, CY_ER, CY_ES, CY_I, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_I, CY_PE, CY_ER, CY_O, CY_EM, CY_TE, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_TE, CY_ER, CY_O, CY_EL, CY_I, CY_SOFT_SIGN, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_SOFT_SIGN, CY_O, CY_EL, CY_DE, CY_TE, CY_BE, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_BE, CY_EL, CY_DE, CY_ZHE, CY_SOFT_SIGN, CY_YU, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - CY_YU, CY_DE, CY_ZHE, CY_E, CY_BE, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - }; - - static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE); - - static { - buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES); - } - } - - private static final class Greek { - // TODO: The following table is solely based on the keyboard layout. Consult with Greek - // speakers on commonly misspelled words/letters. - /* - The Greek layout this represents looks like the following: - ; ς ε ρ τ υ θ ι ο π - α σ δ φ γ η ξ κ λ - ζ χ ψ ω β ν μ - - This gives us the following table: - 'ς', 'ε', 'α', 'σ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ε', 'ς', 'ρ', 'σ', 'δ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ρ', 'ε', 'τ', 'δ', 'φ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'τ', 'ρ', 'υ', 'φ', 'γ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'υ', 'τ', 'θ', 'γ', 'η', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'θ', 'υ', 'ι', 'η', 'ξ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ι', 'θ', 'ο', 'ξ', 'κ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ο', 'ι', 'π', 'κ', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'π', 'ο', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - 'α', 'ς', 'σ', 'ζ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'σ', 'ς', 'ε', 'α', 'δ', 'ζ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'δ', 'ε', 'ρ', 'σ', 'φ', 'ζ', 'χ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'φ', 'ρ', 'τ', 'δ', 'γ', 'χ', 'ψ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'γ', 'τ', 'υ', 'φ', 'η', 'ψ', 'ω', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'η', 'υ', 'θ', 'γ', 'ξ', 'ω', 'β', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ξ', 'θ', 'ι', 'η', 'κ', 'β', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'κ', 'ι', 'ο', 'ξ', 'λ', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'λ', 'ο', 'π', 'κ', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - 'ζ', 'α', 'σ', 'δ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'χ', 'σ', 'δ', 'φ', 'ζ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ψ', 'δ', 'φ', 'γ', 'χ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ω', 'φ', 'γ', 'η', 'ψ', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'β', 'γ', 'η', 'ξ', 'ω', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'ν', 'η', 'ξ', 'κ', 'β', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'μ', 'ξ', 'κ', 'λ', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - Using the following characters: - */ - private static final int GR_FINAL_SIGMA = '\u03C2'; // ς - private static final int GR_EPSILON = '\u03B5'; // ε - private static final int GR_RHO = '\u03C1'; // ρ - private static final int GR_TAU = '\u03C4'; // τ - private static final int GR_UPSILON = '\u03C5'; // υ - private static final int GR_THETA = '\u03B8'; // θ - private static final int GR_IOTA = '\u03B9'; // ι - private static final int GR_OMICRON = '\u03BF'; // ο - private static final int GR_PI = '\u03C0'; // π - private static final int GR_ALPHA = '\u03B1'; // α - private static final int GR_SIGMA = '\u03C3'; // σ - private static final int GR_DELTA = '\u03B4'; // δ - private static final int GR_PHI = '\u03C6'; // φ - private static final int GR_GAMMA = '\u03B3'; // γ - private static final int GR_ETA = '\u03B7'; // η - private static final int GR_XI = '\u03BE'; // ξ - private static final int GR_KAPPA = '\u03BA'; // κ - private static final int GR_LAMDA = '\u03BB'; // λ - private static final int GR_ZETA = '\u03B6'; // ζ - private static final int GR_CHI = '\u03C7'; // χ - private static final int GR_PSI = '\u03C8'; // ψ - private static final int GR_OMEGA = '\u03C9'; // ω - private static final int GR_BETA = '\u03B2'; // β - private static final int GR_NU = '\u03BD'; // ν - private static final int GR_MU = '\u03BC'; // μ - static final int[] PROXIMITY = { - // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter, - // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's. - // The number of rows must be exactly PROXIMITY_GRID_HEIGHT. - GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_SIGMA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_EPSILON, GR_FINAL_SIGMA, GR_RHO, GR_SIGMA, GR_DELTA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_RHO, GR_EPSILON, GR_TAU, GR_DELTA, GR_PHI, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_TAU, GR_RHO, GR_UPSILON, GR_PHI, GR_GAMMA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_UPSILON, GR_TAU, GR_THETA, GR_GAMMA, GR_ETA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_THETA, GR_UPSILON, GR_IOTA, GR_ETA, GR_XI, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_IOTA, GR_THETA, GR_OMICRON, GR_XI, GR_KAPPA, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_OMICRON, GR_IOTA, GR_PI, GR_KAPPA, GR_LAMDA, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_PI, GR_OMICRON, GR_LAMDA, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - GR_ALPHA, GR_FINAL_SIGMA, GR_SIGMA, GR_ZETA, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_SIGMA, GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_DELTA, GR_ZETA, GR_CHI, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_DELTA, GR_EPSILON, GR_RHO, GR_SIGMA, GR_PHI, GR_ZETA, GR_CHI, GR_PSI, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_PHI, GR_RHO, GR_TAU, GR_DELTA, GR_GAMMA, GR_CHI, GR_PSI, GR_OMEGA, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_GAMMA, GR_TAU, GR_UPSILON, GR_PHI, GR_ETA, GR_PSI, GR_OMEGA, GR_BETA, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_ETA, GR_UPSILON, GR_THETA, GR_GAMMA, GR_XI, GR_OMEGA, GR_BETA, GR_NU, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_XI, GR_THETA, GR_IOTA, GR_ETA, GR_KAPPA, GR_BETA, GR_NU, GR_MU, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_KAPPA, GR_IOTA, GR_OMICRON, GR_XI, GR_LAMDA, GR_NU, GR_MU, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_LAMDA, GR_OMICRON, GR_PI, GR_KAPPA, GR_MU, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - - GR_ZETA, GR_ALPHA, GR_SIGMA, GR_DELTA, GR_CHI, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_CHI, GR_SIGMA, GR_DELTA, GR_PHI, GR_ZETA, GR_PSI, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_PSI, GR_DELTA, GR_PHI, GR_GAMMA, GR_CHI, GR_OMEGA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_OMEGA, GR_PHI, GR_GAMMA, GR_ETA, GR_PSI, GR_BETA, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_BETA, GR_GAMMA, GR_ETA, GR_XI, GR_OMEGA, GR_NU, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_NU, GR_ETA, GR_XI, GR_KAPPA, GR_BETA, GR_MU, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - GR_MU, GR_XI, GR_KAPPA, GR_LAMDA, GR_NU, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - }; - - static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE); - - static { - buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES); - } - } - - private static int[] getProximityForScript(final int script) { - switch (script) { - case AndroidSpellCheckerService.SCRIPT_LATIN: - return Latin.PROXIMITY; - case AndroidSpellCheckerService.SCRIPT_CYRILLIC: - return Cyrillic.PROXIMITY; - case AndroidSpellCheckerService.SCRIPT_GREEK: - return Greek.PROXIMITY; - default: - throw new RuntimeException("Wrong script supplied: " + script); - } - } - - private static int getIndexOfCodeForScript(final int codePoint, final int script) { - switch (script) { - case AndroidSpellCheckerService.SCRIPT_LATIN: - return Latin.INDICES.get(codePoint, NOT_AN_INDEX); - case AndroidSpellCheckerService.SCRIPT_CYRILLIC: - return Cyrillic.INDICES.get(codePoint, NOT_AN_INDEX); - case AndroidSpellCheckerService.SCRIPT_GREEK: - return Greek.INDICES.get(codePoint, NOT_AN_INDEX); - default: - throw new RuntimeException("Wrong script supplied: " + script); - } - } - - // Returns (Y << 16) + X to avoid creating a temporary object. This is okay because - // X and Y are limited to PROXIMITY_GRID_WIDTH resp. PROXIMITY_GRID_HEIGHT which is very - // inferior to 1 << 16 - // As an exception, this returns NOT_A_COORDINATE_PAIR if the key is not on the grid - public static int getXYForCodePointAndScript(final int codePoint, final int script) { - final int index = getIndexOfCodeForScript(codePoint, script); - if (NOT_AN_INDEX == index) return NOT_A_COORDINATE_PAIR; - final int y = index / PROXIMITY_GRID_WIDTH; - final int x = index % PROXIMITY_GRID_WIDTH; - if (y > PROXIMITY_GRID_HEIGHT) { - // Safety check, should be entirely useless - throw new RuntimeException("Wrong y coordinate in spell checker proximity"); - } - return (y << 16) + x; - } -}