1/*
2 * Copyright (C) 2012 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#ifndef LATINIME_PROXIMITY_INFO_STATE_H
18#define LATINIME_PROXIMITY_INFO_STATE_H
19
20#include <bitset>
21#include <cstring> // for memset()
22#include <stdint.h>
23#include <string>
24#include <vector>
25
26#include "char_utils.h"
27#include "defines.h"
28#include "hash_map_compat.h"
29
30namespace latinime {
31
32class ProximityInfo;
33
34class ProximityInfoState {
35 public:
36    typedef std::bitset<MAX_KEY_COUNT_IN_A_KEYBOARD> NearKeycodesSet;
37    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
38    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
39    static const float NOT_A_DISTANCE_FLOAT;
40    static const int NOT_A_CODE;
41
42    /////////////////////////////////////////
43    // Defined in proximity_info_state.cpp //
44    /////////////////////////////////////////
45    void initInputParams(const int pointerId, const float maxPointToKeyLength,
46            const ProximityInfo *proximityInfo, const int32_t *const inputCodes,
47            const int inputSize, const int *xCoordinates, const int *yCoordinates,
48            const int *const times, const int *const pointerIds, const bool isGeometric);
49
50    /////////////////////////////////////////
51    // Defined here                        //
52    /////////////////////////////////////////
53    ProximityInfoState()
54            : mProximityInfo(0), mMaxPointToKeyLength(0),
55              mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(),
56              mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
57              mIsContinuationPossible(false), mInputXs(), mInputYs(), mTimes(), mInputIndice(),
58              mDistanceCache(), mLengthCache(), mRelativeSpeeds(), mNearKeysVector(),
59              mTouchPositionCorrectionEnabled(false), mInputSize(0) {
60        memset(mInputCodes, 0, sizeof(mInputCodes));
61        memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
62        memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
63    }
64
65    virtual ~ProximityInfoState() {}
66
67    inline unsigned short getPrimaryCharAt(const int index) const {
68        return getProximityCharsAt(index)[0];
69    }
70
71    inline bool existsCharInProximityAt(const int index, const int c) const {
72        const int *chars = getProximityCharsAt(index);
73        int i = 0;
74        while (chars[i] > 0 && i < MAX_PROXIMITY_CHARS_SIZE_INTERNAL) {
75            if (chars[i++] == c) {
76                return true;
77            }
78        }
79        return false;
80    }
81
82    inline bool existsAdjacentProximityChars(const int index) const {
83        if (index < 0 || index >= mInputSize) return false;
84        const int currentChar = getPrimaryCharAt(index);
85        const int leftIndex = index - 1;
86        if (leftIndex >= 0 && existsCharInProximityAt(leftIndex, currentChar)) {
87            return true;
88        }
89        const int rightIndex = index + 1;
90        if (rightIndex < mInputSize && existsCharInProximityAt(rightIndex, currentChar)) {
91            return true;
92        }
93        return false;
94    }
95
96    // In the following function, c is the current character of the dictionary word
97    // currently examined.
98    // currentChars is an array containing the keys close to the character the
99    // user actually typed at the same position. We want to see if c is in it: if so,
100    // then the word contains at that position a character close to what the user
101    // typed.
102    // What the user typed is actually the first character of the array.
103    // proximityIndex is a pointer to the variable where getMatchedProximityId returns
104    // the index of c in the proximity chars of the input index.
105    // Notice : accented characters do not have a proximity list, so they are alone
106    // in their list. The non-accented version of the character should be considered
107    // "close", but not the other keys close to the non-accented version.
108    inline ProximityType getMatchedProximityId(const int index,
109            const unsigned short c, const bool checkProximityChars, int *proximityIndex = 0) const {
110        const int *currentChars = getProximityCharsAt(index);
111        const int firstChar = currentChars[0];
112        const unsigned short baseLowerC = toBaseLowerCase(c);
113
114        // The first char in the array is what user typed. If it matches right away,
115        // that means the user typed that same char for this pos.
116        if (firstChar == baseLowerC || firstChar == c) {
117            return EQUIVALENT_CHAR;
118        }
119
120        if (!checkProximityChars) return UNRELATED_CHAR;
121
122        // If the non-accented, lowercased version of that first character matches c,
123        // then we have a non-accented version of the accented character the user
124        // typed. Treat it as a close char.
125        if (toBaseLowerCase(firstChar) == baseLowerC)
126            return NEAR_PROXIMITY_CHAR;
127
128        // Not an exact nor an accent-alike match: search the list of close keys
129        int j = 1;
130        while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL
131                && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
132            const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
133            if (matched) {
134                if (proximityIndex) {
135                    *proximityIndex = j;
136                }
137                return NEAR_PROXIMITY_CHAR;
138            }
139            ++j;
140        }
141        if (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL
142                && currentChars[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
143            ++j;
144            while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL
145                    && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
146                const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
147                if (matched) {
148                    if (proximityIndex) {
149                        *proximityIndex = j;
150                    }
151                    return ADDITIONAL_PROXIMITY_CHAR;
152                }
153                ++j;
154            }
155        }
156
157        // Was not included, signal this as an unrelated character.
158        return UNRELATED_CHAR;
159    }
160
161    inline int getNormalizedSquaredDistance(
162            const int inputIndex, const int proximityIndex) const {
163        return mNormalizedSquaredDistances[
164                inputIndex * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + proximityIndex];
165    }
166
167    inline const unsigned short *getPrimaryInputWord() const {
168        return mPrimaryInputWord;
169    }
170
171    inline bool touchPositionCorrectionEnabled() const {
172        return mTouchPositionCorrectionEnabled;
173    }
174
175    inline bool sameAsTyped(const unsigned short *word, int length) const {
176        if (length != mInputSize) {
177            return false;
178        }
179        const int *inputCodes = mInputCodes;
180        while (length--) {
181            if (static_cast<unsigned int>(*inputCodes) != static_cast<unsigned int>(*word)) {
182                return false;
183            }
184            inputCodes += MAX_PROXIMITY_CHARS_SIZE_INTERNAL;
185            word++;
186        }
187        return true;
188    }
189
190    int getDuration(const int index) const;
191
192    bool isUsed() const {
193        return mInputSize > 0;
194    }
195
196    uint32_t size() const {
197        return mInputSize;
198    }
199
200    int getInputX(const int index) const {
201        return mInputXs[index];
202    }
203
204    int getInputY(const int index) const {
205        return mInputYs[index];
206    }
207
208    int getLengthCache(const int index) const {
209        return mLengthCache[index];
210    }
211
212    bool isContinuationPossible() const {
213        return mIsContinuationPossible;
214    }
215
216    float getPointToKeyLength(const int inputIndex, const int charCode, const float scale) const;
217
218    int getSpaceY() const;
219
220    int32_t getAllPossibleChars(
221            const size_t startIndex, int32_t *const filter, const int32_t filterSize) const;
222
223    float getRelativeSpeed(const int index) const {
224        return mRelativeSpeeds[index];
225    }
226 private:
227    DISALLOW_COPY_AND_ASSIGN(ProximityInfoState);
228    typedef hash_map_compat<int, float> NearKeysDistanceMap;
229    /////////////////////////////////////////
230    // Defined in proximity_info_state.cpp //
231    /////////////////////////////////////////
232    float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const;
233
234    float calculateSquaredDistanceFromSweetSpotCenter(
235            const int keyIndex, const int inputIndex) const;
236
237    bool pushTouchPoint(const int inputIndex, const int nodeChar, int x, int y, const int time,
238            const bool sample, const bool isLastPoint,
239            NearKeysDistanceMap *const currentNearKeysDistances,
240            const NearKeysDistanceMap *const prevNearKeysDistances,
241            const NearKeysDistanceMap *const prevPrevNearKeysDistances);
242    /////////////////////////////////////////
243    // Defined here                        //
244    /////////////////////////////////////////
245    inline float square(const float x) const { return x * x; }
246
247    bool hasInputCoordinates() const {
248        return mInputXs.size() > 0 && mInputYs.size() > 0;
249    }
250
251    inline const int *getProximityCharsAt(const int index) const {
252        return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
253    }
254
255    float updateNearKeysDistances(const int x, const int y,
256            NearKeysDistanceMap *const currentNearKeysDistances);
257    bool isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances,
258            const NearKeysDistanceMap *const prevNearKeysDistances,
259            const NearKeysDistanceMap *const prevPrevNearKeysDistances) const;
260    float getPointScore(
261            const int x, const int y, const int time, const bool last, const float nearest,
262            const NearKeysDistanceMap *const currentNearKeysDistances,
263            const NearKeysDistanceMap *const prevNearKeysDistances,
264            const NearKeysDistanceMap *const prevPrevNearKeysDistances) const;
265    bool checkAndReturnIsContinuationPossible(const int inputSize, const int *const xCoordinates,
266            const int *const yCoordinates, const int *const times);
267    void popInputData();
268
269    // const
270    const ProximityInfo *mProximityInfo;
271    float mMaxPointToKeyLength;
272    bool mHasTouchPositionCorrectionData;
273    int mMostCommonKeyWidthSquare;
274    std::string mLocaleStr;
275    int mKeyCount;
276    int mCellHeight;
277    int mCellWidth;
278    int mGridHeight;
279    int mGridWidth;
280    bool mIsContinuationPossible;
281
282    std::vector<int> mInputXs;
283    std::vector<int> mInputYs;
284    std::vector<int> mTimes;
285    std::vector<int> mInputIndice;
286    std::vector<float> mDistanceCache;
287    std::vector<int>  mLengthCache;
288    std::vector<float> mRelativeSpeeds;
289    std::vector<NearKeycodesSet> mNearKeysVector;
290    bool mTouchPositionCorrectionEnabled;
291    int32_t mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL];
292    int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL];
293    int mInputSize;
294    unsigned short mPrimaryInputWord[MAX_WORD_LENGTH_INTERNAL];
295};
296} // namespace latinime
297#endif // LATINIME_PROXIMITY_INFO_STATE_H
298