proximity_info.cpp revision ccebd5cefe0b6b17676edd8639f62bb708a7dd2e
18fbd55229243cb66c03d5ea1f79dfb39f596590dsatok/*
28fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Copyright (C) 2011 The Android Open Source Project
38fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
48fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Licensed under the Apache License, Version 2.0 (the "License");
58fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * you may not use this file except in compliance with the License.
68fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * You may obtain a copy of the License at
78fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
88fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *      http://www.apache.org/licenses/LICENSE-2.0
98fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
108fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Unless required by applicable law or agreed to in writing, software
118fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * distributed under the License is distributed on an "AS IS" BASIS,
128fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * See the License for the specific language governing permissions and
148fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * limitations under the License.
158fbd55229243cb66c03d5ea1f79dfb39f596590dsatok */
168fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
17f1008c550168e50f930ea1e043000b395ce0f129Ken Wakasa#include <cstring>
188fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
19817e517e463cb32726ff5a62196ac8744848e29bsatok#define LOG_TAG "LatinIME: proximity_info.cpp"
20817e517e463cb32726ff5a62196ac8744848e29bsatok
21552c3c27f04e6769e40cffbce3a9e8eed1269294satok#include "additional_proximity_chars.h"
2277e8e81ad95cfc1eb8f8407fc872674b8d08bbe9Ken Wakasa#include "char_utils.h"
233b088a2f365a9ce06f58243c83cb961ea2920b7eKen Wakasa#include "defines.h"
246b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka#include "geometry_utils.h"
25bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa#include "jni.h"
268fbd55229243cb66c03d5ea1f79dfb39f596590dsatok#include "proximity_info.h"
278fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
288fbd55229243cb66c03d5ea1f79dfb39f596590dsatoknamespace latinime {
29ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa
30162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa/* static */ const float ProximityInfo::NOT_A_DISTANCE_FLOAT = -1.0f;
31162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa
326e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasastatic AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray,
336e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasa        jsize len, jint *buffer) {
34bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    if (jArray && buffer) {
35bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        env->GetIntArrayRegion(jArray, 0, len, buffer);
36bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    } else if (buffer) {
3744d9c1ebfc2a847233190f6201ae97b22df30ae7Ken Wakasa        memset(buffer, 0, len * sizeof(buffer[0]));
38de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima    }
39de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima}
40de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima
416e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasastatic AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray,
426e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasa        jsize len, jfloat *buffer) {
43bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    if (jArray && buffer) {
44bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        env->GetFloatArrayRegion(jArray, 0, len, buffer);
45bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    } else if (buffer) {
4644d9c1ebfc2a847233190f6201ae97b22df30ae7Ken Wakasa        memset(buffer, 0, len * sizeof(buffer[0]));
47bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    }
48bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa}
49bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa
50015114592460cca82e5196f2c2e2eff23f9d97aeKen WakasaProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int maxProximityCharsSize,
51552c3c27f04e6769e40cffbce3a9e8eed1269294satok        const int keyboardWidth, const int keyboardHeight, const int gridWidth,
52bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars,
53bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates,
54bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
55bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
56bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        const jfloatArray sweetSpotRadii)
57162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa        : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), GRID_WIDTH(gridWidth),
58162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa          GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
59a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok          MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
60817e517e463cb32726ff5a62196ac8744848e29bsatok          CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
610e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima          CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
62258bfe66e0fcfc89b59534a9cc7f50ff07d5f78dYusuke Nojima          KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
6395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi          KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight),
64a4c1f1c1fde5e9492523842dd95a4c9f17f40c3aYusuke Nojima          HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
65a4c1f1c1fde5e9492523842dd95a4c9f17f40c3aYusuke Nojima                  && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
66162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa                  && sweetSpotCenterYs && sweetSpotRadii),
671d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa          mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
68132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang                  /* proximityGridLength */]),
69132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang          mCodeToKeyMap() {
701035bc990d9d704d8cf1002548e5dddb3ba96797satok    const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
71817e517e463cb32726ff5a62196ac8744848e29bsatok    if (DEBUG_PROXIMITY_INFO) {
729fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok        AKLOGI("Create proximity info array %d", proximityGridLength);
73817e517e463cb32726ff5a62196ac8744848e29bsatok    }
74015114592460cca82e5196f2c2e2eff23f9d97aeKen Wakasa    const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr);
759e0c711a6230af1db0753af401804c95e4bee69dKen Wakasa    if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
769e0c711a6230af1db0753af401804c95e4bee69dKen Wakasa        AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
77ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa        ASSERT(false);
789e0c711a6230af1db0753af401804c95e4bee69dKen Wakasa    }
799e0c711a6230af1db0753af401804c95e4bee69dKen Wakasa    memset(mLocaleStr, 0, sizeof(mLocaleStr));
809e0c711a6230af1db0753af401804c95e4bee69dKen Wakasa    env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr);
81bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityGridLength, mProximityCharsArray);
82bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
83bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
84bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths);
85bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights);
86f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCodePoints);
87bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
88bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
89bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
906b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    initializeG();
910e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima}
920e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima
938fbd55229243cb66c03d5ea1f79dfb39f596590dsatokProximityInfo::~ProximityInfo() {
948fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    delete[] mProximityCharsArray;
958fbd55229243cb66c03d5ea1f79dfb39f596590dsatok}
96817e517e463cb32726ff5a62196ac8744848e29bsatok
97817e517e463cb32726ff5a62196ac8744848e29bsatokinline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const {
983c4bb7747d1a16d6b9d2d34992bad250069632a7satok    return ((y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH))
99817e517e463cb32726ff5a62196ac8744848e29bsatok            * MAX_PROXIMITY_CHARS_SIZE;
100817e517e463cb32726ff5a62196ac8744848e29bsatok}
101817e517e463cb32726ff5a62196ac8744848e29bsatok
102817e517e463cb32726ff5a62196ac8744848e29bsatokbool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
103744dab691e45ff8c5ca9745ee673f50060bcb7a9satok    if (x < 0 || y < 0) {
104744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        if (DEBUG_DICT) {
1059fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok            AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
106f2789819bd005b5b0581e8439601b5501306327dKen Wakasa            // TODO: Enable this assertion.
107ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa            //ASSERT(false);
108744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        }
109744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        return false;
110744dab691e45ff8c5ca9745ee673f50060bcb7a9satok    }
111744dab691e45ff8c5ca9745ee673f50060bcb7a9satok
112817e517e463cb32726ff5a62196ac8744848e29bsatok    const int startIndex = getStartIndexFromCoordinates(x, y);
113817e517e463cb32726ff5a62196ac8744848e29bsatok    if (DEBUG_PROXIMITY_INFO) {
1149fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok        AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
115817e517e463cb32726ff5a62196ac8744848e29bsatok    }
1161d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa    int *proximityCharsArray = mProximityCharsArray;
117817e517e463cb32726ff5a62196ac8744848e29bsatok    for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
118817e517e463cb32726ff5a62196ac8744848e29bsatok        if (DEBUG_PROXIMITY_INFO) {
1199fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok            AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
120817e517e463cb32726ff5a62196ac8744848e29bsatok        }
1213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
122817e517e463cb32726ff5a62196ac8744848e29bsatok            return true;
123817e517e463cb32726ff5a62196ac8744848e29bsatok        }
124817e517e463cb32726ff5a62196ac8744848e29bsatok    }
125817e517e463cb32726ff5a62196ac8744848e29bsatok    return false;
1268fbd55229243cb66c03d5ea1f79dfb39f596590dsatok}
127ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa
1280edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataokafloat ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
129e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka        const int keyId, const int x, const int y) const {
1300edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    const static float verticalSweetSpotScaleForGeometric = 1.1f;
1310edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    const bool correctTouchPosition = hasTouchPositionCorrectionData();
1320edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    const float centerX = static_cast<float>(correctTouchPosition
1330edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka            ? getSweetSpotCenterXAt(keyId)
1340edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka            : getKeyCenterXOfKeyIdG(keyId));
1350edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    const float visualKeyCenterY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId));
1360edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    float centerY;
1370edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    if (correctTouchPosition) {
1380edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka        const float sweetSpotCenterY = static_cast<float>(getSweetSpotCenterYAt(keyId));
1390edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka        const float gapY = sweetSpotCenterY - visualKeyCenterY;
1400edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka        centerY = visualKeyCenterY + gapY * verticalSweetSpotScaleForGeometric;
1410edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    } else {
1420edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka        centerY = visualKeyCenterY;
1430edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka    }
144e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    const float touchX = static_cast<float>(x);
145e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    const float touchY = static_cast<float>(y);
146e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    const float keyWidth = static_cast<float>(getMostCommonKeyWidth());
147e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    return getNormalizedSquaredDistanceFloat(centerX, centerY, touchX, touchY, keyWidth);
148e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka}
149e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka
1509df4a4527a9bc2e671f644d6e2ec0121385740ecsatokint ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const {
151081616cd2f472295449268cecb570771b969cba3Jean Chalard    if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
152a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int left = mKeyXCoordinates[keyId];
153a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int top = mKeyYCoordinates[keyId];
1541caff47ecdfcf413df709371a919cf9377e26bf7satok    const int right = left + mKeyWidths[keyId];
155a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int bottom = top + mKeyHeights[keyId];
156a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int edgeX = x < left ? left : (x > right ? right : x);
157a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int edgeY = y < top ? top : (y > bottom ? bottom : y);
158a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int dx = x - edgeX;
159a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int dy = y - edgeY;
160a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    return dx * dx + dy * dy;
161a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok}
162a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok
163a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satokvoid ProximityInfo::calculateNearbyKeyCodes(
1641d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa        const int x, const int y, const int primaryKey, int *inputCodes) const {
1651d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa    int *proximityCharsArray = mProximityCharsArray;
166a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    int insertPos = 0;
167a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    inputCodes[insertPos++] = primaryKey;
168a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok    const int startIndex = getStartIndexFromCoordinates(x, y);
16952612a0d1b0ce7796fa0a0b50bfda172ebc2a5efJean Chalard    if (startIndex >= 0) {
17088ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard        for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
1711d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa            const int c = proximityCharsArray[startIndex + i];
17288ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            if (c < KEYCODE_SPACE || c == primaryKey) {
17388ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                continue;
17488ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            }
175f2789819bd005b5b0581e8439601b5501306327dKen Wakasa            const int keyIndex = getKeyIndexOf(c);
17688ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            const bool onKey = isOnKey(keyIndex, x, y);
17788ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            const int distance = squaredDistanceToEdge(keyIndex, x, y);
17888ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) {
17988ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                inputCodes[insertPos++] = c;
18088ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
18188ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    if (DEBUG_DICT) {
182ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa                        ASSERT(false);
18388ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    }
18488ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    return;
1850cb2097a45a41875ec2265da316eb770565b6706satok                }
186a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok            }
187a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok        }
18888ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard        const int additionalProximitySize =
189015114592460cca82e5196f2c2e2eff23f9d97aeKen Wakasa                AdditionalProximityChars::getAdditionalCharsSize(mLocaleStr, primaryKey);
19088ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard        if (additionalProximitySize > 0) {
19188ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
19288ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
1933094d12cdcf0583b44f1b32468f0189b530d8c73Jean Chalard                if (DEBUG_DICT) {
194ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa                    ASSERT(false);
1953094d12cdcf0583b44f1b32468f0189b530d8c73Jean Chalard                }
1963094d12cdcf0583b44f1b32468f0189b530d8c73Jean Chalard                return;
1971caff47ecdfcf413df709371a919cf9377e26bf7satok            }
1981caff47ecdfcf413df709371a919cf9377e26bf7satok
1991d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa            const int *additionalProximityChars =
200015114592460cca82e5196f2c2e2eff23f9d97aeKen Wakasa                    AdditionalProximityChars::getAdditionalChars(mLocaleStr, primaryKey);
20188ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard            for (int j = 0; j < additionalProximitySize; ++j) {
2021d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa                const int ac = additionalProximityChars[j];
20388ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                int k = 0;
20488ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                for (; k < insertPos; ++k) {
2051d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa                    if (ac == inputCodes[k]) {
20688ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                        break;
20788ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    }
2085eec574cf0eb6b8ec23723b5f566563453edd42fsatok                }
20988ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                if (k < insertPos) {
21088ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    continue;
2110cb2097a45a41875ec2265da316eb770565b6706satok                }
21288ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                inputCodes[insertPos++] = ac;
21388ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
21488ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    if (DEBUG_DICT) {
215ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa                        ASSERT(false);
21688ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    }
21788ec125cfcbb06e84f611dd26097efa9731979b7Jean Chalard                    return;
2183094d12cdcf0583b44f1b32468f0189b530d8c73Jean Chalard                }
2190cb2097a45a41875ec2265da316eb770565b6706satok            }
2205eec574cf0eb6b8ec23723b5f566563453edd42fsatok        }
22152612a0d1b0ce7796fa0a0b50bfda172ebc2a5efJean Chalard    }
2220cb2097a45a41875ec2265da316eb770565b6706satok    // Add a delimiter for the proximity characters
2231caff47ecdfcf413df709371a919cf9377e26bf7satok    for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
224f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        inputCodes[i] = NOT_A_CODE_POINT;
2251caff47ecdfcf413df709371a919cf9377e26bf7satok    }
226a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok}
227a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok
228f2789819bd005b5b0581e8439601b5501306327dKen Wakasaint ProximityInfo::getKeyIndexOf(const int c) const {
2291caff47ecdfcf413df709371a919cf9377e26bf7satok    if (KEY_COUNT == 0) {
230a4c1f1c1fde5e9492523842dd95a4c9f17f40c3aYusuke Nojima        // We do not have the coordinate data
231bbc25607f01cf9a0cdbc3e8664b27c7f26bd6e18Jean Chalard        return NOT_AN_INDEX;
23216717159fffc7731669143a8e9ed866e7d88ecefYusuke Nojima    }
233ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (c == NOT_A_CODE_POINT) {
234ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return NOT_AN_INDEX;
235ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
2361d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa    const int lowerCode = toLowerCase(c);
237f34ec5aa9557d9986a296c3e636b5c1ab42ff641Tom Ouyang    hash_map_compat<int, int>::const_iterator mapPos = mCodeToKeyMap.find(lowerCode);
238132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang    if (mapPos != mCodeToKeyMap.end()) {
239132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang        return mapPos->second;
24016717159fffc7731669143a8e9ed866e7d88ecefYusuke Nojima    }
241132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang    return NOT_AN_INDEX;
24216717159fffc7731669143a8e9ed866e7d88ecefYusuke Nojima}
243efb63246c2e5df29d62416d48f62e2b57b14de7cSatoshi Kataoka
244f2789819bd005b5b0581e8439601b5501306327dKen Wakasaint ProximityInfo::getCodePointOf(const int keyIndex) const {
2456b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
246f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        return NOT_A_CODE_POINT;
2476b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
248f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    return mKeyIndexToCodePointG[keyIndex];
2496b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2506b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
2516b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataokavoid ProximityInfo::initializeG() {
252e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    // TODO: Optimize
2536b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    for (int i = 0; i < KEY_COUNT; ++i) {
254f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        const int code = mKeyCodePoints[i];
2551d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa        const int lowerCode = toLowerCase(code);
2566b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
2576b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
258132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang        mCodeToKeyMap[lowerCode] = i;
259132168519e1d681ea1b8fd7fcf283155a0b3997eTom Ouyang        mKeyIndexToCodePointG[i] = lowerCode;
2606b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
2616b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    for (int i = 0; i < KEY_COUNT; i++) {
2626b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mKeyKeyDistancesG[i][i] = 0;
2636b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        for (int j = i + 1; j < KEY_COUNT; j++) {
264bcec82de66f52655593dc233346f11468f5077a0Ken Wakasa            mKeyKeyDistancesG[i][j] = getDistanceInt(
2656b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka                    mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
2666b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka            mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
2676b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        }
2686b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
2696b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2706b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
2715964d4e607008d29cca3bc07c878fbc7eb540a1bKen Wakasaint ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const {
272f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    return getKeyCenterXOfKeyIdG(getKeyIndexOf(charCode));
2736b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2746b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
2755964d4e607008d29cca3bc07c878fbc7eb540a1bKen Wakasaint ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const {
276f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    return getKeyCenterYOfKeyIdG(getKeyIndexOf(charCode));
2776b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2786b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
2795964d4e607008d29cca3bc07c878fbc7eb540a1bKen Wakasaint ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const {
2806b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyId >= 0) {
2816b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        return mCenterXsG[keyId];
2826b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
2836b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    return 0;
2846b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2856b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
2865964d4e607008d29cca3bc07c878fbc7eb540a1bKen Wakasaint ProximityInfo::getKeyCenterYOfKeyIdG(int keyId) const {
2876b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyId >= 0) {
2886b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        return mCenterYsG[keyId];
2896b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
2906b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    return 0;
2916b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2926b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
293ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagiint ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
2946b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyId0 >= 0 && keyId1 >= 0) {
2956b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        return mKeyKeyDistancesG[keyId0][keyId1];
2966b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
29707aea409ba400da22067b1048bf2bd00c07c4e4cJean Chalard    return MAX_POINT_TO_KEY_LENGTH;
2986b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
299ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa} // namespace latinime
300