Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cstring>
     18 #include <cmath>
     19 
     20 #define LOG_TAG "LatinIME: proximity_info.cpp"
     21 
     22 #include "additional_proximity_chars.h"
     23 #include "char_utils.h"
     24 #include "defines.h"
     25 #include "geometry_utils.h"
     26 #include "jni.h"
     27 #include "proximity_info.h"
     28 #include "proximity_info_params.h"
     29 
     30 namespace latinime {
     31 
     32 static AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray,
     33         jsize len, jint *buffer) {
     34     if (jArray && buffer) {
     35         env->GetIntArrayRegion(jArray, 0, len, buffer);
     36     } else if (buffer) {
     37         memset(buffer, 0, len * sizeof(buffer[0]));
     38     }
     39 }
     40 
     41 static AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray,
     42         jsize len, jfloat *buffer) {
     43     if (jArray && buffer) {
     44         env->GetFloatArrayRegion(jArray, 0, len, buffer);
     45     } else if (buffer) {
     46         memset(buffer, 0, len * sizeof(buffer[0]));
     47     }
     48 }
     49 
     50 ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr,
     51         const int keyboardWidth, const int keyboardHeight, const int gridWidth,
     52         const int gridHeight, const int mostCommonKeyWidth, const int mostCommonKeyHeight,
     53         const jintArray proximityChars, const int keyCount, const jintArray keyXCoordinates,
     54         const jintArray keyYCoordinates, const jintArray keyWidths, const jintArray keyHeights,
     55         const jintArray keyCharCodes, const jfloatArray sweetSpotCenterXs,
     56         const jfloatArray sweetSpotCenterYs, const jfloatArray sweetSpotRadii)
     57         : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
     58           MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
     59           MOST_COMMON_KEY_HEIGHT(mostCommonKeyHeight),
     60           NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(1.0f +
     61                   SQUARE_FLOAT(static_cast<float>(mostCommonKeyHeight) /
     62                           static_cast<float>(mostCommonKeyWidth))),
     63           CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
     64           CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
     65           KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
     66           KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight),
     67           KEYBOARD_HYPOTENUSE(hypotf(KEYBOARD_WIDTH, KEYBOARD_HEIGHT)),
     68           HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
     69                   && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
     70                   && sweetSpotCenterYs && sweetSpotRadii),
     71           mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
     72                   /* proximityCharsLength */]),
     73           mCodeToKeyMap() {
     74     /* Let's check the input array length here to make sure */
     75     const jsize proximityCharsLength = env->GetArrayLength(proximityChars);
     76     if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) {
     77         AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength);
     78         ASSERT(false);
     79         return;
     80     }
     81     if (DEBUG_PROXIMITY_INFO) {
     82         AKLOGI("Create proximity info array %d", proximityCharsLength);
     83     }
     84     const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr);
     85     if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
     86         AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
     87         ASSERT(false);
     88     }
     89     memset(mLocaleStr, 0, sizeof(mLocaleStr));
     90     env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr);
     91     safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityCharsLength,
     92             mProximityCharsArray);
     93     safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
     94     safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
     95     safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths);
     96     safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights);
     97     safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCodePoints);
     98     safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
     99     safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
    100     safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
    101     initializeG();
    102 }
    103 
    104 ProximityInfo::~ProximityInfo() {
    105     delete[] mProximityCharsArray;
    106 }
    107 
    108 bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
    109     if (x < 0 || y < 0) {
    110         if (DEBUG_DICT) {
    111             AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
    112             // TODO: Enable this assertion.
    113             //ASSERT(false);
    114         }
    115         return false;
    116     }
    117 
    118     const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(x, y,
    119             CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
    120     if (DEBUG_PROXIMITY_INFO) {
    121         AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
    122     }
    123     int *proximityCharsArray = mProximityCharsArray;
    124     for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
    125         if (DEBUG_PROXIMITY_INFO) {
    126             AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
    127         }
    128         if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
    129             return true;
    130         }
    131     }
    132     return false;
    133 }
    134 
    135 float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
    136         const int keyId, const int x, const int y, const float verticalScale) const {
    137     const bool correctTouchPosition = hasTouchPositionCorrectionData();
    138     const float centerX = static_cast<float>(correctTouchPosition ? getSweetSpotCenterXAt(keyId)
    139             : getKeyCenterXOfKeyIdG(keyId));
    140     const float visualKeyCenterY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId));
    141     float centerY;
    142     if (correctTouchPosition) {
    143         const float sweetSpotCenterY = static_cast<float>(getSweetSpotCenterYAt(keyId));
    144         const float gapY = sweetSpotCenterY - visualKeyCenterY;
    145         centerY = visualKeyCenterY + gapY * verticalScale;
    146     } else {
    147         centerY = visualKeyCenterY;
    148     }
    149     const float touchX = static_cast<float>(x);
    150     const float touchY = static_cast<float>(y);
    151     const float keyWidth = static_cast<float>(getMostCommonKeyWidth());
    152     return ProximityInfoUtils::getSquaredDistanceFloat(centerX, centerY, touchX, touchY)
    153             / SQUARE_FLOAT(keyWidth);
    154 }
    155 
    156 int ProximityInfo::getCodePointOf(const int keyIndex) const {
    157     if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
    158         return NOT_A_CODE_POINT;
    159     }
    160     return mKeyIndexToCodePointG[keyIndex];
    161 }
    162 
    163 void ProximityInfo::initializeG() {
    164     // TODO: Optimize
    165     for (int i = 0; i < KEY_COUNT; ++i) {
    166         const int code = mKeyCodePoints[i];
    167         const int lowerCode = toLowerCase(code);
    168         mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
    169         mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
    170         mCodeToKeyMap[lowerCode] = i;
    171         mKeyIndexToCodePointG[i] = lowerCode;
    172     }
    173     for (int i = 0; i < KEY_COUNT; i++) {
    174         mKeyKeyDistancesG[i][i] = 0;
    175         for (int j = i + 1; j < KEY_COUNT; j++) {
    176             mKeyKeyDistancesG[i][j] = getDistanceInt(
    177                     mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
    178             mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
    179         }
    180     }
    181 }
    182 
    183 int ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const {
    184     return getKeyCenterXOfKeyIdG(
    185             ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
    186 }
    187 
    188 int ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const {
    189     return getKeyCenterYOfKeyIdG(
    190             ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
    191 }
    192 
    193 int ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const {
    194     if (keyId >= 0) {
    195         return mCenterXsG[keyId];
    196     }
    197     return 0;
    198 }
    199 
    200 int ProximityInfo::getKeyCenterYOfKeyIdG(int keyId) const {
    201     if (keyId >= 0) {
    202         return mCenterYsG[keyId];
    203     }
    204     return 0;
    205 }
    206 
    207 int ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
    208     if (keyId0 >= 0 && keyId1 >= 0) {
    209         return mKeyKeyDistancesG[keyId0][keyId1];
    210     }
    211     return MAX_VALUE_FOR_WEIGHTING;
    212 }
    213 } // namespace latinime
    214