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

Unified Diff: third_party/android_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: format README and CHROMIUM.diff 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 side-by-side diff with in-line comments
Download patch
Index: third_party/android_prediction/suggest/core/layout/proximity_info.cpp
diff --git a/third_party/android_prediction/suggest/core/layout/proximity_info.cpp b/third_party/android_prediction/suggest/core/layout/proximity_info.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ffd977bacfa440c7eca0e7200cdcf9923d82af7d
--- /dev/null
+++ b/third_party/android_prediction/suggest/core/layout/proximity_info.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LatinIME: proximity_info.cpp"
+
+#include "third_party/android_prediction/suggest/core/layout/proximity_info.h"
+
+#include <algorithm>
+#include <cstring>
+#include <cmath>
+
+#include "third_party/android_prediction/defines.h"
+#include "third_party/android_prediction/suggest/core/layout/additional_proximity_chars.h"
+#include "third_party/android_prediction/suggest/core/layout/geometry_utils.h"
+#include "third_party/android_prediction/suggest/core/layout/proximity_info_params.h"
+#include "third_party/android_prediction/utils/char_utils.h"
+
+namespace latinime {
+
+static AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(const int *jArray,
+ int len, int *buffer) {
+ if (jArray && buffer) {
+ for (int i = 0; i < len; i++) {
+ buffer[i] = jArray[i];
+ }
+ } else if (buffer) {
+ memset(buffer, 0, len * sizeof(buffer[0]));
+ }
+}
+
+static AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(const float *jArray,
+ int len, float *buffer) {
+ if (jArray && buffer) {
+ for (int i = 0; i < len; i++) {
+ buffer[i] = jArray[i];
+ }
+ } else if (buffer) {
+ memset(buffer, 0, len * sizeof(buffer[0]));
+ }
+}
+
+ProximityInfo::ProximityInfo(const std::string localeJStr,
+ const int keyboardWidth, const int keyboardHeight, const int gridWidth,
+ const int gridHeight, const int mostCommonKeyWidth, const int mostCommonKeyHeight,
+ int *proximityChars, int proximitySize, const int keyCount, const int *keyXCoordinates,
+ const int *keyYCoordinates, const int *keyWidths, const int *keyHeights,
+ const int *keyCharCodes, const float *sweetSpotCenterXs,
+ const float *sweetSpotCenterYs, const float *sweetSpotRadii)
+ : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
+ MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
+ NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(1.0f +
+ GeometryUtils::SQUARE_FLOAT(static_cast<float>(mostCommonKeyHeight) /
+ static_cast<float>(mostCommonKeyWidth))),
+ CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
+ CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
+ KEY_COUNT(std::min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
+ KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight),
+ KEYBOARD_HYPOTENUSE(hypotf(KEYBOARD_WIDTH, KEYBOARD_HEIGHT)),
+ HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
+ && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
+ && sweetSpotCenterYs && sweetSpotRadii),
+ mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
+ /* proximityCharsLength */]),
+ mLowerCodePointToKeyMap() {
+ /* Let's check the input array length here to make sure */
+ int proximityCharsLength = proximitySize;
+ if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) {
+ AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength);
+ ASSERT(false);
+ return;
+ }
+ if (DEBUG_PROXIMITY_INFO) {
+ AKLOGI("Create proximity info array %d", proximityCharsLength);
+ }
+ const int localeCStrUtf8Length = localeJStr.length();
+ if (localeCStrUtf8Length >= MAX_LOCALE_STRING_LENGTH) {
+ AKLOGI("Locale string length too long: length=%d", localeCStrUtf8Length);
+ ASSERT(false);
+ }
+ memset(mLocaleStr, 0, sizeof(mLocaleStr));
+ for (int i = 0; i < localeCStrUtf8Length; i++) {
+ mLocaleStr[i] = localeJStr[i];
+ }
+ safeGetOrFillZeroIntArrayRegion(proximityChars, proximityCharsLength,
+ mProximityCharsArray);
+ safeGetOrFillZeroIntArrayRegion(keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
+ safeGetOrFillZeroIntArrayRegion(keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
+ safeGetOrFillZeroIntArrayRegion(keyWidths, KEY_COUNT, mKeyWidths);
+ safeGetOrFillZeroIntArrayRegion(keyHeights, KEY_COUNT, mKeyHeights);
+ safeGetOrFillZeroIntArrayRegion(keyCharCodes, KEY_COUNT, mKeyCodePoints);
+ safeGetOrFillZeroFloatArrayRegion(sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
+ safeGetOrFillZeroFloatArrayRegion(sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
+ safeGetOrFillZeroFloatArrayRegion(sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
+ initializeG();
+}
+
+ProximityInfo::~ProximityInfo() {
+ delete[] mProximityCharsArray;
+}
+
+bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
+ if (x < 0 || y < 0) {
+ if (DEBUG_DICT) {
+ AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
+ // TODO: Enable this assertion.
+ //ASSERT(false);
+ }
+ return false;
+ }
+
+ const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(x, y,
+ CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
+ if (DEBUG_PROXIMITY_INFO) {
+ AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
+ }
+ int *proximityCharsArray = mProximityCharsArray;
+ for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
+ if (DEBUG_PROXIMITY_INFO) {
+ AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
+ }
+ if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
+ return true;
+ }
+ }
+ return false;
+}
+
+float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
+ const int keyId, const int x, const int y, const bool isGeometric) const {
+ const float centerX = static_cast<float>(getKeyCenterXOfKeyIdG(keyId, x, isGeometric));
+ const float centerY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId, y, isGeometric));
+ const float touchX = static_cast<float>(x);
+ const float touchY = static_cast<float>(y);
+ return ProximityInfoUtils::getSquaredDistanceFloat(centerX, centerY, touchX, touchY)
+ / GeometryUtils::SQUARE_FLOAT(static_cast<float>(getMostCommonKeyWidth()));
+}
+
+int ProximityInfo::getCodePointOf(const int keyIndex) const {
+ if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
+ return NOT_A_CODE_POINT;
+ }
+ return mKeyIndexToLowerCodePointG[keyIndex];
+}
+
+int ProximityInfo::getOriginalCodePointOf(const int keyIndex) const {
+ if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
+ return NOT_A_CODE_POINT;
+ }
+ return mKeyIndexToOriginalCodePoint[keyIndex];
+}
+
+void ProximityInfo::initializeG() {
+ // TODO: Optimize
+ for (int i = 0; i < KEY_COUNT; ++i) {
+ const int code = mKeyCodePoints[i];
+ const int lowerCode = CharUtils::toLowerCase(code);
+ mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
+ mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
+ if (hasTouchPositionCorrectionData()) {
+ // Computes sweet spot center points for geometric input.
+ const float verticalScale = ProximityInfoParams::VERTICAL_SWEET_SPOT_SCALE_G;
+ const float sweetSpotCenterY = static_cast<float>(mSweetSpotCenterYs[i]);
+ const float gapY = sweetSpotCenterY - mCenterYsG[i];
+ mSweetSpotCenterYsG[i] = static_cast<int>(mCenterYsG[i] + gapY * verticalScale);
+ }
+ mLowerCodePointToKeyMap[lowerCode] = i;
+ mKeyIndexToOriginalCodePoint[i] = code;
+ mKeyIndexToLowerCodePointG[i] = lowerCode;
+ }
+ for (int i = 0; i < KEY_COUNT; i++) {
+ mKeyKeyDistancesG[i][i] = 0;
+ for (int j = i + 1; j < KEY_COUNT; j++) {
+ if (hasTouchPositionCorrectionData()) {
+ // Computes distances using sweet spots if they exist.
+ // We have two types of Y coordinate sweet spots, for geometric and for the others.
+ // The sweet spots for geometric input are used for calculating key-key distances
+ // here.
+ mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
+ mSweetSpotCenterXs[i], mSweetSpotCenterYsG[i],
+ mSweetSpotCenterXs[j], mSweetSpotCenterYsG[j]);
+ } else {
+ mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
+ mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
+ }
+ mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
+ }
+ }
+}
+
+// referencePointX is used only for keys wider than most common key width. When the referencePointX
+// is NOT_A_COORDINATE, this method calculates the return value without using the line segment.
+// isGeometric is currently not used because we don't have extra X coordinates sweet spots for
+// geometric input.
+int ProximityInfo::getKeyCenterXOfKeyIdG(
+ const int keyId, const int referencePointX, const bool isGeometric) const {
+ if (keyId < 0) {
+ return 0;
+ }
+ int centerX = (hasTouchPositionCorrectionData()) ? static_cast<int>(mSweetSpotCenterXs[keyId])
+ : mCenterXsG[keyId];
+ const int keyWidth = mKeyWidths[keyId];
+ if (referencePointX != NOT_A_COORDINATE
+ && keyWidth > getMostCommonKeyWidth()) {
+ // For keys wider than most common keys, we use a line segment instead of the center point;
+ // thus, centerX is adjusted depending on referencePointX.
+ const int keyWidthHalfDiff = (keyWidth - getMostCommonKeyWidth()) / 2;
+ if (referencePointX < centerX - keyWidthHalfDiff) {
+ centerX -= keyWidthHalfDiff;
+ } else if (referencePointX > centerX + keyWidthHalfDiff) {
+ centerX += keyWidthHalfDiff;
+ } else {
+ centerX = referencePointX;
+ }
+ }
+ return centerX;
+}
+
+// When the referencePointY is NOT_A_COORDINATE, this method calculates the return value without
+// using the line segment.
+int ProximityInfo::getKeyCenterYOfKeyIdG(
+ const int keyId, const int referencePointY, const bool isGeometric) const {
+ // TODO: Remove "isGeometric" and have separate "proximity_info"s for gesture and typing.
+ if (keyId < 0) {
+ return 0;
+ }
+ int centerY;
+ if (!hasTouchPositionCorrectionData()) {
+ centerY = mCenterYsG[keyId];
+ } else if (isGeometric) {
+ centerY = static_cast<int>(mSweetSpotCenterYsG[keyId]);
+ } else {
+ centerY = static_cast<int>(mSweetSpotCenterYs[keyId]);
+ }
+ if (referencePointY != NOT_A_COORDINATE &&
+ centerY + mKeyHeights[keyId] > KEYBOARD_HEIGHT && centerY < referencePointY) {
+ // When the distance between center point and bottom edge of the keyboard is shorter than
+ // the key height, we assume the key is located at the bottom row of the keyboard.
+ // The center point is extended to the bottom edge for such keys.
+ return referencePointY;
+ }
+ return centerY;
+}
+
+int ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
+ if (keyId0 >= 0 && keyId1 >= 0) {
+ return mKeyKeyDistancesG[keyId0][keyId1];
+ }
+ return MAX_VALUE_FOR_WEIGHTING;
+}
+} // namespace latinime

Powered by Google App Engine
This is Rietveld 408576698