Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: third_party/prediction/suggest/core/layout/proximity_info.cpp

Issue 1247903003: Add spellcheck and word suggestion to the prediction service (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "third_party/prediction/suggest/core/layout/proximity_info.h"
20
21 #include <algorithm>
22 #include <cstring>
23 #include <cmath>
24
25 #include "third_party/prediction/defines.h"
26 #include "third_party/prediction/suggest/core/layout/additional_proximity_chars. h"
27 #include "third_party/prediction/suggest/core/layout/geometry_utils.h"
28 #include "third_party/prediction/suggest/core/layout/proximity_info_params.h"
29 #include "third_party/prediction/utils/char_utils.h"
30
31 namespace latinime {
32
33 static AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(const int* jArray,
34 int len,
35 int* buffer) {
36 if (jArray && buffer) {
37 for (int i = 0; i < len; i++) {
38 buffer[i] = jArray[i];
39 }
40 } else if (buffer) {
41 memset(buffer, 0, len * sizeof(buffer[0]));
42 }
43 }
44
45 static AK_FORCE_INLINE void
46 safeGetOrFillZeroFloatArrayRegion(const float* jArray, int len, float* buffer) {
47 if (jArray && buffer) {
48 for (int i = 0; i < len; i++) {
49 buffer[i] = jArray[i];
50 }
51 } else if (buffer) {
52 memset(buffer, 0, len * sizeof(buffer[0]));
53 }
54 }
55
56 ProximityInfo::ProximityInfo(const std::string localeJStr,
57 const int keyboardWidth,
58 const int keyboardHeight,
59 const int gridWidth,
60 const int gridHeight,
61 const int mostCommonKeyWidth,
62 const int mostCommonKeyHeight,
63 int* proximityChars,
64 int proximitySize,
65 const int keyCount,
66 const int* keyXCoordinates,
67 const int* keyYCoordinates,
68 const int* keyWidths,
69 const int* keyHeights,
70 const int* keyCharCodes,
71 const float* sweetSpotCenterXs,
72 const float* sweetSpotCenterYs,
73 const float* sweetSpotRadii)
74 : GRID_WIDTH(gridWidth),
75 GRID_HEIGHT(gridHeight),
76 MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
77 MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
78 NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(
79 1.0f +
80 GeometryUtils::SQUARE_FLOAT(static_cast<float>(mostCommonKeyHeight) /
81 static_cast<float>(mostCommonKeyWidth))),
82 CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
83 CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
84 KEY_COUNT(std::min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
85 KEYBOARD_WIDTH(keyboardWidth),
86 KEYBOARD_HEIGHT(keyboardHeight),
87 KEYBOARD_HYPOTENUSE(hypotf(KEYBOARD_WIDTH, KEYBOARD_HEIGHT)),
88 HAS_TOUCH_POSITION_CORRECTION_DATA(
89 keyCount > 0 && keyXCoordinates && keyYCoordinates && keyWidths &&
90 keyHeights &&
91 keyCharCodes &&
92 sweetSpotCenterXs &&
93 sweetSpotCenterYs &&
94 sweetSpotRadii),
95 mProximityCharsArray(
96 new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
97 /* proximityCharsLength */]),
98 mLowerCodePointToKeyMap() {
99 /* Let's check the input array length here to make sure */
100 int proximityCharsLength = proximitySize;
101 if (proximityCharsLength !=
102 GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) {
103 AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength);
104 ASSERT(false);
105 return;
106 }
107 if (DEBUG_PROXIMITY_INFO) {
108 AKLOGI("Create proximity info array %d", proximityCharsLength);
109 }
110 const int localeCStrUtf8Length = localeJStr.length();
111 if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
112 AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
113 ASSERT(false);
114 }
115 memset(mLocaleStr, 0, sizeof(mLocaleStr));
116 for (int i = 0; i < localeCStrUtf8Length; i++) {
117 mLocaleStr[i] = localeJStr[i];
118 }
119 safeGetOrFillZeroIntArrayRegion(proximityChars, proximityCharsLength,
120 mProximityCharsArray);
121 safeGetOrFillZeroIntArrayRegion(keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
122 safeGetOrFillZeroIntArrayRegion(keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
123 safeGetOrFillZeroIntArrayRegion(keyWidths, KEY_COUNT, mKeyWidths);
124 safeGetOrFillZeroIntArrayRegion(keyHeights, KEY_COUNT, mKeyHeights);
125 safeGetOrFillZeroIntArrayRegion(keyCharCodes, KEY_COUNT, mKeyCodePoints);
126 safeGetOrFillZeroFloatArrayRegion(sweetSpotCenterXs, KEY_COUNT,
127 mSweetSpotCenterXs);
128 safeGetOrFillZeroFloatArrayRegion(sweetSpotCenterYs, KEY_COUNT,
129 mSweetSpotCenterYs);
130 safeGetOrFillZeroFloatArrayRegion(sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
131 initializeG();
132 }
133
134 ProximityInfo::~ProximityInfo() {
135 delete[] mProximityCharsArray;
136 }
137
138 bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
139 if (x < 0 || y < 0) {
140 if (DEBUG_DICT) {
141 AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
142 // TODO: Enable this assertion.
143 // ASSERT(false);
144 }
145 return false;
146 }
147
148 const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(
149 x, y, CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
150 if (DEBUG_PROXIMITY_INFO) {
151 AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
152 }
153 int* proximityCharsArray = mProximityCharsArray;
154 for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
155 if (DEBUG_PROXIMITY_INFO) {
156 AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
157 }
158 if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
159 return true;
160 }
161 }
162 return false;
163 }
164
165 float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
166 const int keyId,
167 const int x,
168 const int y,
169 const bool isGeometric) const {
170 const float centerX =
171 static_cast<float>(getKeyCenterXOfKeyIdG(keyId, x, isGeometric));
172 const float centerY =
173 static_cast<float>(getKeyCenterYOfKeyIdG(keyId, y, isGeometric));
174 const float touchX = static_cast<float>(x);
175 const float touchY = static_cast<float>(y);
176 return ProximityInfoUtils::getSquaredDistanceFloat(centerX, centerY, touchX,
177 touchY) /
178 GeometryUtils::SQUARE_FLOAT(
179 static_cast<float>(getMostCommonKeyWidth()));
180 }
181
182 int ProximityInfo::getCodePointOf(const int keyIndex) const {
183 if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
184 return NOT_A_CODE_POINT;
185 }
186 return mKeyIndexToLowerCodePointG[keyIndex];
187 }
188
189 int ProximityInfo::getOriginalCodePointOf(const int keyIndex) const {
190 if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
191 return NOT_A_CODE_POINT;
192 }
193 return mKeyIndexToOriginalCodePoint[keyIndex];
194 }
195
196 void ProximityInfo::initializeG() {
197 // TODO: Optimize
198 for (int i = 0; i < KEY_COUNT; ++i) {
199 const int code = mKeyCodePoints[i];
200 const int lowerCode = CharUtils::toLowerCase(code);
201 mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
202 mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
203 if (hasTouchPositionCorrectionData()) {
204 // Computes sweet spot center points for geometric input.
205 const float verticalScale =
206 ProximityInfoParams::VERTICAL_SWEET_SPOT_SCALE_G;
207 const float sweetSpotCenterY = static_cast<float>(mSweetSpotCenterYs[i]);
208 const float gapY = sweetSpotCenterY - mCenterYsG[i];
209 mSweetSpotCenterYsG[i] =
210 static_cast<int>(mCenterYsG[i] + gapY * verticalScale);
211 }
212 mLowerCodePointToKeyMap[lowerCode] = i;
213 mKeyIndexToOriginalCodePoint[i] = code;
214 mKeyIndexToLowerCodePointG[i] = lowerCode;
215 }
216 for (int i = 0; i < KEY_COUNT; i++) {
217 mKeyKeyDistancesG[i][i] = 0;
218 for (int j = i + 1; j < KEY_COUNT; j++) {
219 if (hasTouchPositionCorrectionData()) {
220 // Computes distances using sweet spots if they exist.
221 // We have two types of Y coordinate sweet spots, for geometric and for
222 // the others.
223 // The sweet spots for geometric input are used for calculating key-key
224 // distances
225 // here.
226 mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
227 mSweetSpotCenterXs[i], mSweetSpotCenterYsG[i],
228 mSweetSpotCenterXs[j], mSweetSpotCenterYsG[j]);
229 } else {
230 mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
231 mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
232 }
233 mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
234 }
235 }
236 }
237
238 // referencePointX is used only for keys wider than most common key width. When
239 // the referencePointX
240 // is NOT_A_COORDINATE, this method calculates the return value without using
241 // the line segment.
242 // isGeometric is currently not used because we don't have extra X coordinates
243 // sweet spots for
244 // geometric input.
245 int ProximityInfo::getKeyCenterXOfKeyIdG(const int keyId,
246 const int referencePointX,
247 const bool isGeometric) const {
248 if (keyId < 0) {
249 return 0;
250 }
251 int centerX = (hasTouchPositionCorrectionData())
252 ? static_cast<int>(mSweetSpotCenterXs[keyId])
253 : mCenterXsG[keyId];
254 const int keyWidth = mKeyWidths[keyId];
255 if (referencePointX != NOT_A_COORDINATE &&
256 keyWidth > getMostCommonKeyWidth()) {
257 // For keys wider than most common keys, we use a line segment instead of
258 // the center point;
259 // thus, centerX is adjusted depending on referencePointX.
260 const int keyWidthHalfDiff = (keyWidth - getMostCommonKeyWidth()) / 2;
261 if (referencePointX < centerX - keyWidthHalfDiff) {
262 centerX -= keyWidthHalfDiff;
263 } else if (referencePointX > centerX + keyWidthHalfDiff) {
264 centerX += keyWidthHalfDiff;
265 } else {
266 centerX = referencePointX;
267 }
268 }
269 return centerX;
270 }
271
272 // When the referencePointY is NOT_A_COORDINATE, this method calculates the
273 // return value without
274 // using the line segment.
275 int ProximityInfo::getKeyCenterYOfKeyIdG(const int keyId,
276 const int referencePointY,
277 const bool isGeometric) const {
278 // TODO: Remove "isGeometric" and have separate "proximity_info"s for gesture
279 // and typing.
280 if (keyId < 0) {
281 return 0;
282 }
283 int centerY;
284 if (!hasTouchPositionCorrectionData()) {
285 centerY = mCenterYsG[keyId];
286 } else if (isGeometric) {
287 centerY = static_cast<int>(mSweetSpotCenterYsG[keyId]);
288 } else {
289 centerY = static_cast<int>(mSweetSpotCenterYs[keyId]);
290 }
291 if (referencePointY != NOT_A_COORDINATE &&
292 centerY + mKeyHeights[keyId] > KEYBOARD_HEIGHT &&
293 centerY < referencePointY) {
294 // When the distance between center point and bottom edge of the keyboard is
295 // shorter than
296 // the key height, we assume the key is located at the bottom row of the
297 // keyboard.
298 // The center point is extended to the bottom edge for such keys.
299 return referencePointY;
300 }
301 return centerY;
302 }
303
304 int ProximityInfo::getKeyKeyDistanceG(const int keyId0,
305 const int keyId1) const {
306 if (keyId0 >= 0 && keyId1 >= 0) {
307 return mKeyKeyDistancesG[keyId0][keyId1];
308 }
309 return MAX_VALUE_FOR_WEIGHTING;
310 }
311 } // namespace latinime
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698