From 096f35ff4b5413906e2a339663baf16e5dabaf64 Mon Sep 17 00:00:00 2001
From: Keisuke Kuroyanagi <ksk@google.com>
Date: Fri, 7 Sep 2012 21:04:12 +0900
Subject: [PATCH] Fix the condition of continuation for gesture input and make
 ProximityInfoState incremental.

Change-Id: I69ad295b660e0c4ba5bb29c8d3d8805291ec43a8
---
 native/jni/src/proximity_info_state.cpp | 75 +++++++++++++++++++------
 native/jni/src/proximity_info_state.h   | 17 ++++--
 2 files changed, 70 insertions(+), 22 deletions(-)

diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index 8c3174c0a..a4eb7e353 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -29,6 +29,14 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
         const ProximityInfo *proximityInfo, const int32_t *const inputCodes, const int inputSize,
         const int *const xCoordinates, const int *const yCoordinates, const int *const times,
         const int *const pointerIds, const bool isGeometric) {
+
+    if (isGeometric) {
+        mIsContinuationPossible = checkAndReturnIsContinuationPossible(
+                inputSize, xCoordinates, yCoordinates, times);
+    } else {
+        mIsContinuationPossible = false;
+    }
+
     mProximityInfo = proximityInfo;
     mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData();
     mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare();
@@ -70,19 +78,32 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
 
     ///////////////////////
     // Setup touch points
+    int pushTouchPointStartIndex = 0;
+    int lastSavedInputSize = 0;
     mMaxPointToKeyLength = maxPointToKeyLength;
-    mInputXs.clear();
-    mInputYs.clear();
-    mTimes.clear();
-    mLengthCache.clear();
-    mDistanceCache.clear();
-    mNearKeysVector.clear();
+    if (mIsContinuationPossible && mInputIndice.size() > 1) {
+        // Just update difference.
+        // Two points prior is never skipped. Thus, we pop 2 input point data here.
+        pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2];
+        popInputData();
+        popInputData();
+        lastSavedInputSize = mInputXs.size();
+    } else {
+        // Clear all data.
+        mInputXs.clear();
+        mInputYs.clear();
+        mTimes.clear();
+        mInputIndice.clear();
+        mLengthCache.clear();
+        mDistanceCache.clear();
+        mNearKeysVector.clear();
+    }
     mInputSize = 0;
 
     if (xCoordinates && yCoordinates) {
         const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0);
-        int lastInputIndex = 0;
-        for (int i = 0; i < inputSize; ++i) {
+        int lastInputIndex = pushTouchPointStartIndex;
+        for (int i = lastInputIndex; i < inputSize; ++i) {
             const int pid = pointerIds ? pointerIds[i] : 0;
             if (pointerId == pid) {
                 lastInputIndex = i;
@@ -95,7 +116,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
         NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1];
         NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2];
 
-        for (int i = 0; i < inputSize; ++i) {
+        for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) {
             // Assuming pointerId == 0 if pointerIds is null.
             const int pid = pointerIds ? pointerIds[i] : 0;
             if (pointerId == pid) {
@@ -103,7 +124,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
                 const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i];
                 const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i];
                 const int time = times ? times[i] : -1;
-                if (pushTouchPoint(c, x, y, time, isGeometric, i == lastInputIndex,
+                if (pushTouchPoint(i, c, x, y, time, isGeometric, i == lastInputIndex,
                         currentNearKeysDistances, prevNearKeysDistances,
                         prevPrevNearKeysDistances)) {
                     // Previous point information was popped.
@@ -125,7 +146,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
         const int keyCount = mProximityInfo->getKeyCount();
         mNearKeysVector.resize(mInputSize);
         mDistanceCache.resize(mInputSize * keyCount);
-        for (int i = 0; i < mInputSize; ++i) {
+        for (int i = lastSavedInputSize; i < mInputSize; ++i) {
             mNearKeysVector[i].reset();
             static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
             for (int k = 0; k < keyCount; ++k) {
@@ -146,7 +167,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
                 hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight())
                 * READ_FORWORD_LENGTH_SCALE);
         for (int i = 0; i < mInputSize; ++i) {
-            for (int j = i + 1; j < mInputSize; ++j) {
+            for (int j = max(i + 1, lastSavedInputSize); j < mInputSize; ++j) {
                 if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) {
                     break;
                 }
@@ -199,6 +220,18 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
     }
 }
 
+bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize,
+        const int *const xCoordinates, const int *const yCoordinates, const int *const times) {
+    for (int i = 0; i < mInputSize; ++i) {
+        const int index = mInputIndice[i];
+        if (index > inputSize || xCoordinates[index] != mInputXs[i] ||
+                yCoordinates[index] != mInputYs[i] || times[index] != mTimes[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
 // Calculating point to key distance for all near keys and returning the distance between
 // the given point and the nearest key position.
 float ProximityInfoState::updateNearKeysDistances(const int x, const int y,
@@ -305,8 +338,8 @@ float ProximityInfoState::getPointScore(
 
 // Sampling touch point and pushing information to vectors.
 // Returning if previous point is popped or not.
-bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const int time,
-        const bool sample, const bool isLastPoint,
+bool ProximityInfoState::pushTouchPoint(const int inputIndex, const int nodeChar, int x, int y,
+        const int time, const bool sample, const bool isLastPoint,
         NearKeysDistanceMap *const currentNearKeysDistances,
         const NearKeysDistanceMap *const prevNearKeysDistances,
         const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
@@ -320,10 +353,7 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const
                 currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances);
         if (score < 0) {
             // Pop previous point because it would be useless.
-            mInputXs.pop_back();
-            mInputYs.pop_back();
-            mTimes.pop_back();
-            mLengthCache.pop_back();
+            popInputData();
             size = mInputXs.size();
             popped = true;
         } else {
@@ -371,6 +401,7 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const
     mInputXs.push_back(x);
     mInputYs.push_back(y);
     mTimes.push_back(time);
+    mInputIndice.push_back(inputIndex);
     return popped;
 }
 
@@ -461,4 +492,12 @@ float ProximityInfoState::getAveragePointDuration() const {
     return static_cast<float>(mTimes[mInputSize - 1] - mTimes[0]) / static_cast<float>(mInputSize);
 }
 
+void ProximityInfoState::popInputData() {
+    mInputXs.pop_back();
+    mInputYs.pop_back();
+    mTimes.pop_back();
+    mLengthCache.pop_back();
+    mInputIndice.pop_back();
+}
+
 } // namespace latinime
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index 1d5777347..fce4b5bdc 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -57,9 +57,9 @@ class ProximityInfoState {
             : mProximityInfo(0), mMaxPointToKeyLength(0),
               mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(),
               mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
-              mInputXs(), mInputYs(), mTimes(), mDistanceCache(), mLengthCache(),
-              mNearKeysVector(), mTouchPositionCorrectionEnabled(false),
-              mInputSize(0) {
+              mIsContinuationPossible(false), mInputXs(), mInputYs(), mTimes(), mInputIndice(),
+              mDistanceCache(), mLengthCache(), mNearKeysVector(),
+              mTouchPositionCorrectionEnabled(false), mInputSize(0) {
         memset(mInputCodes, 0, sizeof(mInputCodes));
         memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
         memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
@@ -212,6 +212,10 @@ class ProximityInfoState {
         return mLengthCache[index];
     }
 
+    bool isContinuationPossible() const {
+        return mIsContinuationPossible;
+    }
+
     float getPointToKeyLength(const int inputIndex, const int charCode, const float scale) const;
 
     int getSpaceY() const;
@@ -231,7 +235,7 @@ class ProximityInfoState {
     float calculateSquaredDistanceFromSweetSpotCenter(
             const int keyIndex, const int inputIndex) const;
 
-    bool pushTouchPoint(const int nodeChar, int x, int y, const int time,
+    bool pushTouchPoint(const int inputIndex, const int nodeChar, int x, int y, const int time,
             const bool sample, const bool isLastPoint,
             NearKeysDistanceMap *const currentNearKeysDistances,
             const NearKeysDistanceMap *const prevNearKeysDistances,
@@ -259,6 +263,9 @@ class ProximityInfoState {
             const NearKeysDistanceMap *const currentNearKeysDistances,
             const NearKeysDistanceMap *const prevNearKeysDistances,
             const NearKeysDistanceMap *const prevPrevNearKeysDistances) const;
+    bool checkAndReturnIsContinuationPossible(const int inputSize, const int *const xCoordinates,
+            const int *const yCoordinates, const int *const times);
+    void popInputData();
 
     // const
     const ProximityInfo *mProximityInfo;
@@ -271,10 +278,12 @@ class ProximityInfoState {
     int mCellWidth;
     int mGridHeight;
     int mGridWidth;
+    bool mIsContinuationPossible;
 
     std::vector<int> mInputXs;
     std::vector<int> mInputYs;
     std::vector<int> mTimes;
+    std::vector<int> mInputIndice;
     std::vector<float> mDistanceCache;
     std::vector<int>  mLengthCache;
     std::vector<NearKeycodesSet> mNearKeysVector;