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