Add ability to handle digraphs in gesture and tap typing

Example: Gesture the German word "ueber" and the system will now replace
the transliteration "ue" with the correct u-umlaut.

Bug: 8493920
Change-Id: I03e1d6311b4187b6c7f802d8fef43a50eee12721
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 764c372..63bb200 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -18,6 +18,7 @@
 
 #include "char_utils.h"
 #include "dictionary.h"
+#include "digraph_utils.h"
 #include "proximity_info.h"
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_priority_queue.h"
@@ -221,7 +222,7 @@
 void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const {
     const int inputSize = traverseSession->getInputSize();
     DicNodeVector childDicNodes(TRAVERSAL->getDefaultExpandDicNodeSize());
-    DicNode omissionDicNode;
+    DicNode correctionDicNode;
 
     // TODO: Find more efficient caching
     const bool shouldDepthLevelCache = TRAVERSAL->shouldDepthLevelCache(traverseSession);
@@ -257,7 +258,10 @@
             dicNode.setCached();
         }
 
-        if (isLookAheadCorrection) {
+        if (dicNode.isInDigraph()) {
+            // Finish digraph handling if the node is in the middle of a digraph expansion.
+            processDicNodeAsDigraph(traverseSession, &dicNode);
+        } else if (isLookAheadCorrection) {
             // The algorithm maintains a small set of "deferred" nodes that have not consumed the
             // latest touch point yet. These are needed to apply look-ahead correction operations
             // that require special handling of the latest touch point. For example, with insertions
@@ -291,12 +295,18 @@
                     processDicNodeAsMatch(traverseSession, childDicNode);
                     continue;
                 }
+                if (DigraphUtils::hasDigraphForCodePoint(traverseSession->getDictFlags(),
+                        childDicNode->getNodeCodePoint())) {
+                    correctionDicNode.initByCopy(childDicNode);
+                    correctionDicNode.advanceDigraphIndex();
+                    processDicNodeAsDigraph(traverseSession, &correctionDicNode);
+                }
                 if (allowsErrorCorrections
                         && TRAVERSAL->isOmission(traverseSession, &dicNode, childDicNode)) {
                     // TODO: (Gesture) Change weight between omission and substitution errors
                     // TODO: (Gesture) Terminal node should not be handled as omission
-                    omissionDicNode.initByCopy(childDicNode);
-                    processDicNodeAsOmission(traverseSession, &omissionDicNode);
+                    correctionDicNode.initByCopy(childDicNode);
+                    processDicNodeAsOmission(traverseSession, &correctionDicNode);
                 }
                 const ProximityType proximityType = TRAVERSAL->getProximityType(
                         traverseSession, &dicNode, childDicNode);
@@ -400,6 +410,16 @@
     processExpandedDicNode(traverseSession, childDicNode);
 }
 
+// Process the node codepoint as a digraph. This means that composite glyphs like the German
+// u-umlaut is expanded to the transliteration "ue". Note that this happens in parallel with
+// the normal non-digraph traversal, so both "uber" and "ueber" can be corrected to "[u-umlaut]ber".
+void Suggest::processDicNodeAsDigraph(DicTraverseSession *traverseSession,
+        DicNode *childDicNode) const {
+    weightChildNode(traverseSession, childDicNode);
+    childDicNode->advanceDigraphIndex();
+    processExpandedDicNode(traverseSession, childDicNode);
+}
+
 /**
  * Handle the dicNode as an omission error (e.g., ths => this). Skip the current letter and consider
  * matches for all possible next letters. Note that just skipping the current letter without any
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 6c09b94..136c4e5 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -64,6 +64,7 @@
     void generateFeatures(
             DicTraverseSession *traverseSession, DicNode *dicNode, float *features) const;
     void processDicNodeAsOmission(DicTraverseSession *traverseSession, DicNode *dicNode) const;
+    void processDicNodeAsDigraph(DicTraverseSession *traverseSession, DicNode *dicNode) const;
     void processDicNodeAsTransposition(DicTraverseSession *traverseSession,
             DicNode *dicNode) const;
     void processDicNodeAsInsertion(DicTraverseSession *traverseSession, DicNode *dicNode) const;