blob: 3979cfa9a40b5bfe00f7c4ea0e070ca23b20cbe7 [file] [log] [blame]
satok8fbd5522011-02-22 17:28:55 +09001/*
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
Ken Wakasaf1008c52012-07-31 17:56:40 +090017#include <cstring>
satok8fbd5522011-02-22 17:28:55 +090018
satok817e5172011-03-04 06:06:45 -080019#define LOG_TAG "LatinIME: proximity_info.cpp"
20
satok552c3c22012-03-13 16:33:47 +090021#include "additional_proximity_chars.h"
Ken Wakasa77e8e812012-08-02 19:48:08 +090022#include "char_utils.h"
Ken Wakasa3b088a22012-05-16 23:05:32 +090023#include "defines.h"
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +090024#include "geometry_utils.h"
Ken Wakasabb005f72012-08-08 20:43:47 +090025#include "jni.h"
satok8fbd5522011-02-22 17:28:55 +090026#include "proximity_info.h"
27
28namespace latinime {
Ken Wakasace9e52a2011-06-18 13:09:55 +090029
Ken Wakasa6e663492012-11-03 02:50:47 +090030static AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray,
31 jsize len, jint *buffer) {
Ken Wakasabb005f72012-08-08 20:43:47 +090032 if (jArray && buffer) {
33 env->GetIntArrayRegion(jArray, 0, len, buffer);
34 } else if (buffer) {
Ken Wakasa44d9c1e2012-11-01 17:05:08 +090035 memset(buffer, 0, len * sizeof(buffer[0]));
Yusuke Nojimade2f8422011-09-27 11:15:18 +090036 }
37}
38
Ken Wakasa6e663492012-11-03 02:50:47 +090039static AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray,
40 jsize len, jfloat *buffer) {
Ken Wakasabb005f72012-08-08 20:43:47 +090041 if (jArray && buffer) {
42 env->GetFloatArrayRegion(jArray, 0, len, buffer);
43 } else if (buffer) {
Ken Wakasa44d9c1e2012-11-01 17:05:08 +090044 memset(buffer, 0, len * sizeof(buffer[0]));
Ken Wakasabb005f72012-08-08 20:43:47 +090045 }
46}
47
Ken Wakasa6c224392013-01-22 13:14:53 +090048ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr,
satok552c3c22012-03-13 16:33:47 +090049 const int keyboardWidth, const int keyboardHeight, const int gridWidth,
Ken Wakasabb005f72012-08-08 20:43:47 +090050 const int gridHeight, const int mostCommonKeyWidth, const jintArray proximityChars,
51 const int keyCount, const jintArray keyXCoordinates, const jintArray keyYCoordinates,
52 const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
53 const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
54 const jfloatArray sweetSpotRadii)
Ken Wakasa6c224392013-01-22 13:14:53 +090055 : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
satoka70ee6e2012-03-07 15:12:22 +090056 MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
satok817e5172011-03-04 06:06:45 -080057 CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
Yusuke Nojima0e1f6562011-09-21 12:02:47 +090058 CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
Yusuke Nojima258bfe62011-09-28 12:59:43 +090059 KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
Keisuke Kuroyanagi95a49a52012-09-04 17:00:24 +090060 KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight),
Yusuke Nojimaa4c1f1c2011-10-06 19:12:20 +090061 HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
62 && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
Ken Wakasa162c2112012-08-24 14:51:15 +090063 && sweetSpotCenterYs && sweetSpotRadii),
Ken Wakasa1d516fb2012-12-03 19:43:15 +090064 mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
Ken Wakasa6c224392013-01-22 13:14:53 +090065 /* proximityCharsLength */]),
Tom Ouyang13216852012-09-03 12:50:21 -070066 mCodeToKeyMap() {
Ken Wakasa6c224392013-01-22 13:14:53 +090067 /* Let's check the input array length here to make sure */
68 const jsize proximityCharsLength = env->GetArrayLength(proximityChars);
69 if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) {
70 AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength);
71 ASSERT(false);
72 return;
73 }
satok817e5172011-03-04 06:06:45 -080074 if (DEBUG_PROXIMITY_INFO) {
Ken Wakasa6c224392013-01-22 13:14:53 +090075 AKLOGI("Create proximity info array %d", proximityCharsLength);
satok817e5172011-03-04 06:06:45 -080076 }
Ken Wakasa01511452012-08-09 15:58:15 +090077 const jsize localeCStrUtf8Length = env->GetStringUTFLength(localeJStr);
Ken Wakasa9e0c7112012-08-09 22:26:58 +090078 if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
79 AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
Ken Wakasaccebd5c2013-01-09 15:21:44 +090080 ASSERT(false);
Ken Wakasa9e0c7112012-08-09 22:26:58 +090081 }
82 memset(mLocaleStr, 0, sizeof(mLocaleStr));
83 env->GetStringUTFRegion(localeJStr, 0, env->GetStringLength(localeJStr), mLocaleStr);
Ken Wakasa6c224392013-01-22 13:14:53 +090084 safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityCharsLength,
85 mProximityCharsArray);
Ken Wakasabb005f72012-08-08 20:43:47 +090086 safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
87 safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
88 safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths);
89 safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights);
Ken Wakasaf2789812012-09-04 12:49:46 +090090 safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCodePoints);
Ken Wakasabb005f72012-08-08 20:43:47 +090091 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
92 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
93 safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +090094 initializeG();
Yusuke Nojima0e1f6562011-09-21 12:02:47 +090095}
96
satok8fbd5522011-02-22 17:28:55 +090097ProximityInfo::~ProximityInfo() {
98 delete[] mProximityCharsArray;
99}
satok817e5172011-03-04 06:06:45 -0800100
satok817e5172011-03-04 06:06:45 -0800101bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
satok744dab62011-12-15 22:29:05 +0900102 if (x < 0 || y < 0) {
103 if (DEBUG_DICT) {
satok9fb6f472012-01-13 18:01:22 +0900104 AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
Ken Wakasaf2789812012-09-04 12:49:46 +0900105 // TODO: Enable this assertion.
Ken Wakasaccebd5c2013-01-09 15:21:44 +0900106 //ASSERT(false);
satok744dab62011-12-15 22:29:05 +0900107 }
108 return false;
109 }
110
Ken Wakasa6e2ba9b2013-01-30 19:24:03 +0900111 const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(x, y,
112 CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
satok817e5172011-03-04 06:06:45 -0800113 if (DEBUG_PROXIMITY_INFO) {
satok9fb6f472012-01-13 18:01:22 +0900114 AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
satok817e5172011-03-04 06:06:45 -0800115 }
Ken Wakasa1d516fb2012-12-03 19:43:15 +0900116 int *proximityCharsArray = mProximityCharsArray;
satok817e5172011-03-04 06:06:45 -0800117 for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
118 if (DEBUG_PROXIMITY_INFO) {
satok9fb6f472012-01-13 18:01:22 +0900119 AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
satok817e5172011-03-04 06:06:45 -0800120 }
Satoshi Kataoka3e8c58f2012-06-05 17:55:52 +0900121 if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
satok817e5172011-03-04 06:06:45 -0800122 return true;
123 }
124 }
125 return false;
126}
Ken Wakasace9e52a2011-06-18 13:09:55 +0900127
Satoshi Kataoka0edab9d2012-09-24 18:29:31 +0900128float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
Satoshi Kataokae7398cd2012-08-13 20:20:04 +0900129 const int keyId, const int x, const int y) const {
Satoshi Kataoka0edab9d2012-09-24 18:29:31 +0900130 const static float verticalSweetSpotScaleForGeometric = 1.1f;
131 const bool correctTouchPosition = hasTouchPositionCorrectionData();
132 const float centerX = static_cast<float>(correctTouchPosition
133 ? getSweetSpotCenterXAt(keyId)
134 : getKeyCenterXOfKeyIdG(keyId));
135 const float visualKeyCenterY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId));
136 float centerY;
137 if (correctTouchPosition) {
138 const float sweetSpotCenterY = static_cast<float>(getSweetSpotCenterYAt(keyId));
139 const float gapY = sweetSpotCenterY - visualKeyCenterY;
140 centerY = visualKeyCenterY + gapY * verticalSweetSpotScaleForGeometric;
141 } else {
142 centerY = visualKeyCenterY;
143 }
Satoshi Kataokae7398cd2012-08-13 20:20:04 +0900144 const float touchX = static_cast<float>(x);
145 const float touchY = static_cast<float>(y);
146 const float keyWidth = static_cast<float>(getMostCommonKeyWidth());
Ken Wakasa0c2227a2013-01-21 11:37:54 +0900147 return ProximityInfoUtils::getSquaredDistanceFloat(centerX, centerY, touchX, touchY)
148 / SQUARE_FLOAT(keyWidth);
Satoshi Kataokae7398cd2012-08-13 20:20:04 +0900149}
150
Ken Wakasaf2789812012-09-04 12:49:46 +0900151int ProximityInfo::getCodePointOf(const int keyIndex) const {
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900152 if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
Ken Wakasaf2789812012-09-04 12:49:46 +0900153 return NOT_A_CODE_POINT;
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900154 }
Ken Wakasaf2789812012-09-04 12:49:46 +0900155 return mKeyIndexToCodePointG[keyIndex];
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900156}
157
158void ProximityInfo::initializeG() {
Satoshi Kataokae7398cd2012-08-13 20:20:04 +0900159 // TODO: Optimize
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900160 for (int i = 0; i < KEY_COUNT; ++i) {
Ken Wakasaf2789812012-09-04 12:49:46 +0900161 const int code = mKeyCodePoints[i];
Ken Wakasa1d516fb2012-12-03 19:43:15 +0900162 const int lowerCode = toLowerCase(code);
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900163 mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
164 mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
Tom Ouyang13216852012-09-03 12:50:21 -0700165 mCodeToKeyMap[lowerCode] = i;
166 mKeyIndexToCodePointG[i] = lowerCode;
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900167 }
168 for (int i = 0; i < KEY_COUNT; i++) {
169 mKeyKeyDistancesG[i][i] = 0;
170 for (int j = i + 1; j < KEY_COUNT; j++) {
Satoshi Kataoka47cc5242013-01-21 16:33:24 +0900171 mKeyKeyDistancesG[i][j] = getDistanceInt(
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900172 mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
173 mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
174 }
175 }
176}
177
Ken Wakasa5964d4e2012-09-10 16:49:36 +0900178int ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const {
Satoshi Kataokabf78e132013-01-17 19:46:12 +0900179 return getKeyCenterXOfKeyIdG(
180 ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900181}
182
Ken Wakasa5964d4e2012-09-10 16:49:36 +0900183int ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const {
Satoshi Kataokabf78e132013-01-17 19:46:12 +0900184 return getKeyCenterYOfKeyIdG(
185 ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, charCode, &mCodeToKeyMap));
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900186}
187
Ken Wakasa5964d4e2012-09-10 16:49:36 +0900188int ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const {
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900189 if (keyId >= 0) {
190 return mCenterXsG[keyId];
191 }
192 return 0;
193}
194
Ken Wakasa5964d4e2012-09-10 16:49:36 +0900195int ProximityInfo::getKeyCenterYOfKeyIdG(int keyId) const {
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900196 if (keyId >= 0) {
197 return mCenterYsG[keyId];
198 }
199 return 0;
200}
201
Keisuke Kuroyanagiff74cc32012-10-11 13:08:06 +0900202int ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900203 if (keyId0 >= 0 && keyId1 >= 0) {
204 return mKeyKeyDistancesG[keyId0][keyId1];
205 }
Jean Chalard07aea402012-08-29 20:09:27 +0900206 return MAX_POINT_TO_KEY_LENGTH;
Satoshi Kataoka6b4a1d72012-08-10 15:42:56 +0900207}
Ken Wakasace9e52a2011-06-18 13:09:55 +0900208} // namespace latinime