proximity_info.cpp revision bb005f787f4e00bd832e6a78797be10af2994061
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 <cassert> 18#include <cmath> 19#include <cstring> 20#include <string> 21 22#define LOG_TAG "LatinIME: proximity_info.cpp" 23 24#include "additional_proximity_chars.h" 25#include "char_utils.h" 26#include "defines.h" 27#include "jni.h" 28#include "proximity_info.h" 29 30namespace latinime { 31 32static inline void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray, jsize len, 33 jint *buffer) { 34 if (jArray && buffer) { 35 env->GetIntArrayRegion(jArray, 0, len, buffer); 36 } else if (buffer) { 37 memset(buffer, 0, len); 38 } 39} 40 41static inline void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray, jsize len, 42 jfloat *buffer) { 43 if (jArray && buffer) { 44 env->GetFloatArrayRegion(jArray, 0, len, buffer); 45 } else if (buffer) { 46 memset(buffer, 0, len); 47 } 48} 49 50ProximityInfo::ProximityInfo(JNIEnv *env, const char *localeCStr, const int maxProximityCharsSize, 51 const int keyboardWidth, const int keyboardHeight, const int gridWidth, 52 const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars, 53 const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates, 54 const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes, 55 const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs, 56 const jfloatArray sweetSpotRadii) 57 : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth), 58 KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), 59 MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth), 60 CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), 61 CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight), 62 KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), 63 HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates 64 && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs 65 && sweetSpotCenterYs && sweetSpotRadii), 66 mLocaleStr(localeCStr) { 67 const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; 68 if (DEBUG_PROXIMITY_INFO) { 69 AKLOGI("Create proximity info array %d", proximityGridLength); 70 } 71 mProximityCharsArray = new int32_t[proximityGridLength]; 72 safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityGridLength, mProximityCharsArray); 73 safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates); 74 safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates); 75 safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths); 76 safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights); 77 safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCharCodes); 78 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs); 79 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs); 80 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii); 81 initializeCodeToKeyIndex(); 82} 83 84// Build the reversed look up table from the char code to the index in mKeyXCoordinates, 85// mKeyYCoordinates, mKeyWidths, mKeyHeights, mKeyCharCodes. 86void ProximityInfo::initializeCodeToKeyIndex() { 87 memset(mCodeToKeyIndex, -1, (MAX_CHAR_CODE + 1) * sizeof(mCodeToKeyIndex[0])); 88 for (int i = 0; i < KEY_COUNT; ++i) { 89 const int code = mKeyCharCodes[i]; 90 if (0 <= code && code <= MAX_CHAR_CODE) { 91 mCodeToKeyIndex[code] = i; 92 } 93 } 94} 95 96ProximityInfo::~ProximityInfo() { 97 delete[] mProximityCharsArray; 98} 99 100inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const { 101 return ((y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH)) 102 * MAX_PROXIMITY_CHARS_SIZE; 103} 104 105bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { 106 if (x < 0 || y < 0) { 107 if (DEBUG_DICT) { 108 AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y); 109 assert(false); 110 } 111 return false; 112 } 113 114 const int startIndex = getStartIndexFromCoordinates(x, y); 115 if (DEBUG_PROXIMITY_INFO) { 116 AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y); 117 } 118 int32_t *proximityCharsArray = mProximityCharsArray; 119 for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { 120 if (DEBUG_PROXIMITY_INFO) { 121 AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]); 122 } 123 if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) { 124 return true; 125 } 126 } 127 return false; 128} 129 130int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const { 131 if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case 132 const int left = mKeyXCoordinates[keyId]; 133 const int top = mKeyYCoordinates[keyId]; 134 const int right = left + mKeyWidths[keyId]; 135 const int bottom = top + mKeyHeights[keyId]; 136 const int edgeX = x < left ? left : (x > right ? right : x); 137 const int edgeY = y < top ? top : (y > bottom ? bottom : y); 138 const int dx = x - edgeX; 139 const int dy = y - edgeY; 140 return dx * dx + dy * dy; 141} 142 143void ProximityInfo::calculateNearbyKeyCodes( 144 const int x, const int y, const int32_t primaryKey, int *inputCodes) const { 145 int32_t *proximityCharsArray = mProximityCharsArray; 146 int insertPos = 0; 147 inputCodes[insertPos++] = primaryKey; 148 const int startIndex = getStartIndexFromCoordinates(x, y); 149 if (startIndex >= 0) { 150 for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { 151 const int32_t c = proximityCharsArray[startIndex + i]; 152 if (c < KEYCODE_SPACE || c == primaryKey) { 153 continue; 154 } 155 const int keyIndex = getKeyIndex(c); 156 const bool onKey = isOnKey(keyIndex, x, y); 157 const int distance = squaredDistanceToEdge(keyIndex, x, y); 158 if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) { 159 inputCodes[insertPos++] = c; 160 if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { 161 if (DEBUG_DICT) { 162 assert(false); 163 } 164 return; 165 } 166 } 167 } 168 const int additionalProximitySize = 169 AdditionalProximityChars::getAdditionalCharsSize(&mLocaleStr, primaryKey); 170 if (additionalProximitySize > 0) { 171 inputCodes[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; 172 if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { 173 if (DEBUG_DICT) { 174 assert(false); 175 } 176 return; 177 } 178 179 const int32_t *additionalProximityChars = 180 AdditionalProximityChars::getAdditionalChars(&mLocaleStr, primaryKey); 181 for (int j = 0; j < additionalProximitySize; ++j) { 182 const int32_t ac = additionalProximityChars[j]; 183 int k = 0; 184 for (; k < insertPos; ++k) { 185 if ((int)ac == inputCodes[k]) { 186 break; 187 } 188 } 189 if (k < insertPos) { 190 continue; 191 } 192 inputCodes[insertPos++] = ac; 193 if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) { 194 if (DEBUG_DICT) { 195 assert(false); 196 } 197 return; 198 } 199 } 200 } 201 } 202 // Add a delimiter for the proximity characters 203 for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { 204 inputCodes[i] = NOT_A_CODE; 205 } 206} 207 208int ProximityInfo::getKeyIndex(const int c) const { 209 if (KEY_COUNT == 0) { 210 // We do not have the coordinate data 211 return NOT_AN_INDEX; 212 } 213 const unsigned short baseLowerC = toBaseLowerCase(c); 214 if (baseLowerC > MAX_CHAR_CODE) { 215 return NOT_AN_INDEX; 216 } 217 return mCodeToKeyIndex[baseLowerC]; 218} 219 220// TODO: [Staging] Optimize 221void ProximityInfo::getCenters(int *centerXs, int *centerYs, int *codeToKeyIndex, 222 int *keyToCodeIndex, int *keyCount, int *keyWidth) const { 223 *keyCount = KEY_COUNT; 224 *keyWidth = sqrt(static_cast<float>(MOST_COMMON_KEY_WIDTH_SQUARE)); 225 226 for (int i = 0; i < KEY_COUNT; ++i) { 227 const int code = mKeyCharCodes[i]; 228 const int lowerCode = toBaseLowerCase(code); 229 centerXs[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2; 230 centerYs[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2; 231 codeToKeyIndex[code] = i; 232 if (code != lowerCode && lowerCode >= 0 && lowerCode <= MAX_CHAR_CODE) { 233 codeToKeyIndex[lowerCode] = i; 234 keyToCodeIndex[i] = lowerCode; 235 } else { 236 keyToCodeIndex[i] = code; 237 } 238 } 239} 240} // namespace latinime 241