Handle CFDE_TextEditEngine delegate unexpectedly changing text.

JavaScript might run and change the value into which text
is about to be inserted, so recheck boundaries before
continuing.

Bug: chromium:976753
Change-Id: I7d5e8cf0ccc3be881ab7303fafad53c54d3f6ec2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/56630
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/testing/resources/javascript/xfa_specific/bug_976753.evt b/testing/resources/javascript/xfa_specific/bug_976753.evt
new file mode 100644
index 0000000..beda23a
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_976753.evt
@@ -0,0 +1,6 @@
+mousedown,left,200,95
+mouseup,left,200,95
+charcode,72
+charcode,72
+charcode,72
+charcode,72
diff --git a/testing/resources/javascript/xfa_specific/bug_976753.in b/testing/resources/javascript/xfa_specific/bug_976753.in
new file mode 100644
index 0000000..c9cf91c
--- /dev/null
+++ b/testing/resources/javascript/xfa_specific/bug_976753.in
@@ -0,0 +1,42 @@
+{{header}}
+{{include ../../xfa_catalog_1_0.fragment}}
+{{include ../../xfa_object_2_0.fragment}}
+{{include ../../xfa_preamble_3_0.fragment}}
+{{include ../../xfa_config_4_0.fragment}}
+{{object 5 0}} <<
+  {{steamlen}}
+>>
+stream
+<template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">
+  <subform name="form1" layout="tb" locale="en_US" restoreState="auto">
+    <event activity="docReady" ref="$form">
+      <script>
+        Field0.rawValue = "dog"
+      </script>
+    </event>
+    <field x="0" y="0" w="1000pt" h="1000pt" name="Field0">
+      <event activity="change">
+        <script contentType="application/x-javascript">
+          xfa.host.setFocus('form1.Field1');
+        </script>
+      </event>
+    </field>
+    <field x="100pt" y="100pt" w="100pt" h="100pt" name="Field1">
+      <event activity="enter"  listen="refAndDescendents">
+        <script contentType="application/x-javascript">
+          xfa.host.setFocus('form1.Field0')
+          Field0.rawValue="m9";
+        </script>
+      </event>
+    </field>
+  </subform>
+</template>
+endstream
+endobj
+{{include ../../xfa_locale_6_0.fragment}}
+{{include ../../xfa_postamble_7_0.fragment}}
+{{include ../../xfa_pages_8_0.fragment}}
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/xfa/fde/cfde_texteditengine.cpp b/xfa/fde/cfde_texteditengine.cpp
index 8dfc532..297724a 100644
--- a/xfa/fde/cfde_texteditengine.cpp
+++ b/xfa/fde/cfde_texteditengine.cpp
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <utility>
 
 #include "third_party/base/ptr_util.h"
 #include "xfa/fde/cfde_textout.h"
@@ -268,8 +269,8 @@
   WideString text = request_text;
   if (text.GetLength() == 0)
     return;
-  if (idx > text_length_)
-    idx = text_length_;
+
+  idx = std::min(idx, text_length_);
 
   TextChange change;
   change.selection_start = idx;
@@ -287,9 +288,12 @@
     text = change.text;
     idx = change.selection_start;
 
-    // JS extended the selection, so delete it before we insert.
+    // Delegate extended the selection, so delete it before we insert.
     if (change.selection_end != change.selection_start)
       DeleteSelectedText(RecordOperation::kSkipRecord);
+
+    // Delegate may have changed text entirely, recheck.
+    idx = std::min(idx, text_length_);
   }
 
   size_t length = text.GetLength();
@@ -848,8 +852,13 @@
     if (change.cancelled)
       return WideString();
 
+    // Delegate may have changed the selection range.
     start_idx = change.selection_start;
     length = change.selection_end - change.selection_start;
+
+    // Delegate may have changed text entirely, recheck.
+    if (start_idx >= text_length_)
+      return WideString();
   }
 
   length = std::min(length, text_length_ - start_idx);