Add FORM_ReplaceAndKeepSelection for IME composition

This API is used to simulate IME composition with selection. This will
be sufficient for most CJK IMEs.

Bug: chromium:1253665
Change-Id: Ifa5f878a0d299b9c697b0c616f682b1c031998a4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/103256
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_annot.h b/fpdfsdk/cpdfsdk_annot.h
index 3b1d022..1357594 100644
--- a/fpdfsdk/cpdfsdk_annot.h
+++ b/fpdfsdk/cpdfsdk_annot.h
@@ -75,6 +75,7 @@
   virtual bool Redo() = 0;
   virtual WideString GetText() = 0;
   virtual WideString GetSelectedText() = 0;
+  virtual void ReplaceAndKeepSelection(const WideString& text) = 0;
   virtual void ReplaceSelection(const WideString& text) = 0;
   virtual bool SelectAllText() = 0;
   virtual bool SetIndexSelected(int index, bool selected) = 0;
diff --git a/fpdfsdk/cpdfsdk_baannot.cpp b/fpdfsdk/cpdfsdk_baannot.cpp
index 04ad812..a1751f9 100644
--- a/fpdfsdk/cpdfsdk_baannot.cpp
+++ b/fpdfsdk/cpdfsdk_baannot.cpp
@@ -403,6 +403,8 @@
   return WideString();
 }
 
+void CPDFSDK_BAAnnot::ReplaceAndKeepSelection(const WideString& text) {}
+
 void CPDFSDK_BAAnnot::ReplaceSelection(const WideString& text) {}
 
 bool CPDFSDK_BAAnnot::SelectAllText() {
diff --git a/fpdfsdk/cpdfsdk_baannot.h b/fpdfsdk/cpdfsdk_baannot.h
index 2be9e14..0da13d8 100644
--- a/fpdfsdk/cpdfsdk_baannot.h
+++ b/fpdfsdk/cpdfsdk_baannot.h
@@ -44,6 +44,7 @@
   bool Redo() override;
   WideString GetText() override;
   WideString GetSelectedText() override;
+  void ReplaceAndKeepSelection(const WideString& text) override;
   void ReplaceSelection(const WideString& text) override;
   bool SelectAllText() override;
   bool SetIndexSelected(int index, bool selected) override;
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 83d7783..4c82e7f 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -286,6 +286,12 @@
   return annot->GetSelectedText();
 }
 
+void CPDFSDK_PageView::ReplaceAndKeepSelection(const WideString& text) {
+  CPDFSDK_Annot* annot = GetFocusAnnot();
+  if (annot)
+    annot->ReplaceAndKeepSelection(text);
+}
+
 void CPDFSDK_PageView::ReplaceSelection(const WideString& text) {
   CPDFSDK_Annot* annot = GetFocusAnnot();
   if (annot)
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index 675600f..b95f844 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -66,6 +66,7 @@
 
   WideString GetFocusedFormText();
   WideString GetSelectedText();
+  void ReplaceAndKeepSelection(const WideString& text);
   void ReplaceSelection(const WideString& text);
   bool SelectAllText();
 
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index 22b8be6..4cf176f 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -877,6 +877,13 @@
   return GetInteractiveFormFiller()->GetSelectedText(this);
 }
 
+void CPDFSDK_Widget::ReplaceAndKeepSelection(const WideString& text) {
+  if (IsSignatureWidget())
+    return;
+
+  GetInteractiveFormFiller()->ReplaceAndKeepSelection(this, text);
+}
+
 void CPDFSDK_Widget::ReplaceSelection(const WideString& text) {
   if (IsSignatureWidget())
     return;
diff --git a/fpdfsdk/cpdfsdk_widget.h b/fpdfsdk/cpdfsdk_widget.h
index f63e8a4..ce68cfb 100644
--- a/fpdfsdk/cpdfsdk_widget.h
+++ b/fpdfsdk/cpdfsdk_widget.h
@@ -65,6 +65,7 @@
   bool Redo() override;
   WideString GetText() override;
   WideString GetSelectedText() override;
+  void ReplaceAndKeepSelection(const WideString& text) override;
   void ReplaceSelection(const WideString& text) override;
   bool SelectAllText() override;
   bool SetIndexSelected(int index, bool selected) override;
diff --git a/fpdfsdk/formfiller/cffl_formfield.cpp b/fpdfsdk/formfiller/cffl_formfield.cpp
index 063a919..88fb16a 100644
--- a/fpdfsdk/formfiller/cffl_formfield.cpp
+++ b/fpdfsdk/formfiller/cffl_formfield.cpp
@@ -203,6 +203,17 @@
   return pWnd ? pWnd->GetSelectedText() : WideString();
 }
 
+void CFFL_FormField::ReplaceAndKeepSelection(const WideString& text) {
+  if (!IsValid())
+    return;
+
+  CPWL_Wnd* pWnd = GetPWLWindow(GetCurPageView());
+  if (!pWnd)
+    return;
+
+  pWnd->ReplaceAndKeepSelection(text);
+}
+
 void CFFL_FormField::ReplaceSelection(const WideString& text) {
   if (!IsValid())
     return;
diff --git a/fpdfsdk/formfiller/cffl_formfield.h b/fpdfsdk/formfiller/cffl_formfield.h
index bceb9b0..1ddf730 100644
--- a/fpdfsdk/formfiller/cffl_formfield.h
+++ b/fpdfsdk/formfiller/cffl_formfield.h
@@ -78,6 +78,7 @@
 
   WideString GetText();
   WideString GetSelectedText();
+  void ReplaceAndKeepSelection(const WideString& text);
   void ReplaceSelection(const WideString& text);
   bool SelectAllText();
 
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index f4b0b94..5137429 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -531,6 +531,16 @@
   return pFormField ? pFormField->GetSelectedText() : WideString();
 }
 
+void CFFL_InteractiveFormFiller::ReplaceAndKeepSelection(
+    CPDFSDK_Widget* pWidget,
+    const WideString& text) {
+  CFFL_FormField* pFormField = GetFormField(pWidget);
+  if (!pFormField)
+    return;
+
+  pFormField->ReplaceAndKeepSelection(text);
+}
+
 void CFFL_InteractiveFormFiller::ReplaceSelection(CPDFSDK_Widget* pWidget,
                                                   const WideString& text) {
   CFFL_FormField* pFormField = GetFormField(pWidget);
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index cbfa695..bbf757d 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -126,6 +126,7 @@
 
   WideString GetText(CPDFSDK_Widget* pWidget);
   WideString GetSelectedText(CPDFSDK_Widget* pWidget);
+  void ReplaceAndKeepSelection(CPDFSDK_Widget* pWidget, const WideString& text);
   void ReplaceSelection(CPDFSDK_Widget* pWidget, const WideString& text);
   bool SelectAllText(CPDFSDK_Widget* pWidget);
 
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index 56c1326..8c1a083 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -531,6 +531,17 @@
                                              buffer, buflen);
 }
 
+FPDF_EXPORT void FPDF_CALLCONV
+FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,
+                             FPDF_PAGE page,
+                             FPDF_WIDESTRING wsText) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  if (!pPageView)
+    return;
+
+  pPageView->ReplaceAndKeepSelection(WideStringFromFPDFWideString(wsText));
+}
+
 FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,
                                                      FPDF_PAGE page,
                                                      FPDF_WIDESTRING wsText) {
diff --git a/fpdfsdk/fpdf_formfill_embeddertest.cpp b/fpdfsdk/fpdf_formfill_embeddertest.cpp
index 6b63f4e..ea4af57 100644
--- a/fpdfsdk/fpdf_formfill_embeddertest.cpp
+++ b/fpdfsdk/fpdf_formfill_embeddertest.cpp
@@ -3197,6 +3197,39 @@
   }
 }
 
+TEST_F(FPDFFormFillTextFormEmbedderTest, ReplaceAndKeepSelection) {
+  ScopedFPDFWideString text_to_insert = GetFPDFWideString(L"XYZ");
+  ClickOnFormFieldAtPoint(RegularFormBegin());
+  CheckCanUndo(false);
+  CheckCanRedo(false);
+
+  TypeTextIntoTextField(2, RegularFormBegin());
+  CheckFocusedFieldText(L"AB");
+  CheckSelection(L"");
+  SelectTextWithKeyboard(1, FWL_VKEY_Right, RegularFormBegin());
+  CheckSelection(L"A");
+
+  FORM_ReplaceAndKeepSelection(form_handle(), page(), text_to_insert.get());
+  CheckFocusedFieldText(L"XYZB");
+  CheckSelection(L"XYZ");
+  CheckCanUndo(true);
+  CheckCanRedo(false);
+
+  PerformUndo();
+  CheckFocusedFieldText(L"AB");
+  CheckCanUndo(true);
+  CheckCanRedo(true);
+
+  SelectTextWithKeyboard(1, FWL_VKEY_Left, RegularFormEnd());
+  CheckSelection(L"B");
+
+  FORM_ReplaceAndKeepSelection(form_handle(), page(), text_to_insert.get());
+  CheckFocusedFieldText(L"AXYZ");
+  CheckSelection(L"XYZ");
+  CheckCanUndo(true);
+  CheckCanRedo(false);
+}
+
 TEST_F(FPDFFormFillTextFormEmbedderTest, ReplaceSelection) {
   ScopedFPDFWideString text_to_insert = GetFPDFWideString(L"XYZ");
   ClickOnFormFieldAtPoint(RegularFormBegin());
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index e85db77..e9231d7 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -299,6 +299,7 @@
     CHK(FORM_OnRButtonDown);
     CHK(FORM_OnRButtonUp);
     CHK(FORM_Redo);
+    CHK(FORM_ReplaceAndKeepSelection);
     CHK(FORM_ReplaceSelection);
     CHK(FORM_SelectAllText);
     CHK(FORM_SetFocusedAnnot);
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_widget.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_widget.cpp
index b0ef53b..1367c1a 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_widget.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_widget.cpp
@@ -411,6 +411,12 @@
   return widget_handler->GetSelectedText(GetXFAFFWidget());
 }
 
+void CPDFXFA_Widget::ReplaceAndKeepSelection(const WideString& text) {
+  // XFA does not seem to support IME input at all. Therefore we don't bother
+  // to keep selection for IMEs.
+  ReplaceSelection(text);
+}
+
 void CPDFXFA_Widget::ReplaceSelection(const WideString& text) {
   CXFA_FFWidgetHandler* widget_handler = GetWidgetHandler();
   if (widget_handler)
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_widget.h b/fpdfsdk/fpdfxfa/cpdfxfa_widget.h
index 38d6537..1a74213 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_widget.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_widget.h
@@ -38,6 +38,7 @@
   bool Redo() override;
   WideString GetText() override;
   WideString GetSelectedText() override;
+  void ReplaceAndKeepSelection(const WideString& text) override;
   void ReplaceSelection(const WideString& text) override;
   bool SelectAllText() override;
   bool SetIndexSelected(int index, bool selected) override;
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
index dde7652..50c19f4 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
@@ -62,6 +62,11 @@
   return WideString();
 }
 
+void CPWL_ComboBox::ReplaceAndKeepSelection(const WideString& text) {
+  if (m_pEdit)
+    m_pEdit->ReplaceAndKeepSelection(text);
+}
+
 void CPWL_ComboBox::ReplaceSelection(const WideString& text) {
   if (m_pEdit)
     m_pEdit->ReplaceSelection(text);
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
index 6d74a97..bb8fa0c 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.h
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
@@ -40,6 +40,7 @@
   void KillFocus() override;
   WideString GetText() override;
   WideString GetSelectedText() override;
+  void ReplaceAndKeepSelection(const WideString& text) override;
   void ReplaceSelection(const WideString& text) override;
   bool SelectAllText() override;
   bool CanUndo() override;
diff --git a/fpdfsdk/pwl/cpwl_combo_box_edit_embeddertest.cpp b/fpdfsdk/pwl/cpwl_combo_box_edit_embeddertest.cpp
index 529d9ad..3a9d8ef 100644
--- a/fpdfsdk/pwl/cpwl_combo_box_edit_embeddertest.cpp
+++ b/fpdfsdk/pwl/cpwl_combo_box_edit_embeddertest.cpp
@@ -265,3 +265,19 @@
   GetCPWLComboBox()->ReplaceSelection(L"Hello");
   EXPECT_STREQ(L"ABCDEHello", GetCPWLComboBox()->GetText().c_str());
 }
+
+TEST_F(CPWLComboBoxEditEmbedderTest, ReplaceAndKeepSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(1, 3);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLComboBox()->GetText().c_str());
+  GetCPWLComboBox()->ReplaceAndKeepSelection(L"xyz");
+  EXPECT_STREQ(L"AxyzDEFGHIJ", GetCPWLComboBox()->GetText().c_str());
+  EXPECT_STREQ(L"xyz", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->SetEditSelection(4, 1);
+  GetCPWLComboBox()->ReplaceAndKeepSelection(L"12");
+  EXPECT_STREQ(L"A12DEFGHIJ", GetCPWLComboBox()->GetText().c_str());
+  EXPECT_STREQ(L"12", GetCPWLComboBox()->GetSelectedText().c_str());
+}
diff --git a/fpdfsdk/pwl/cpwl_edit.cpp b/fpdfsdk/pwl/cpwl_edit.cpp
index 9fce555..f0b4d35 100644
--- a/fpdfsdk/pwl/cpwl_edit.cpp
+++ b/fpdfsdk/pwl/cpwl_edit.cpp
@@ -487,6 +487,10 @@
   return m_pEditImpl->GetSelectedText();
 }
 
+void CPWL_Edit::ReplaceAndKeepSelection(const WideString& text) {
+  m_pEditImpl->ReplaceAndKeepSelection(text);
+}
+
 void CPWL_Edit::ReplaceSelection(const WideString& text) {
   m_pEditImpl->ReplaceSelection(text);
 }
diff --git a/fpdfsdk/pwl/cpwl_edit.h b/fpdfsdk/pwl/cpwl_edit.h
index c879148..696e32c 100644
--- a/fpdfsdk/pwl/cpwl_edit.h
+++ b/fpdfsdk/pwl/cpwl_edit.h
@@ -63,6 +63,7 @@
   void SetCursor() override;
   WideString GetText() override;
   WideString GetSelectedText() override;
+  void ReplaceAndKeepSelection(const WideString& text) override;
   void ReplaceSelection(const WideString& text) override;
   bool SelectAllText() override;
   bool CanUndo() override;
diff --git a/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
index a076924..f0e13d2 100644
--- a/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
@@ -4,6 +4,8 @@
 
 #include "fpdfsdk/pwl/cpwl_edit.h"
 
+#include <utility>
+
 #include "fpdfsdk/cpdfsdk_annotiterator.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_helpers.h"
@@ -420,3 +422,21 @@
   GetCPWLEdit()->SetText(L"Foo\n\rBar");
   EXPECT_STREQ(L"FooBar", GetCPWLEdit()->GetText().c_str());
 }
+
+TEST_F(CPWLEditEmbedderTest, ReplaceAndKeepSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(1, 3);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLEdit()->GetText().c_str());
+  GetCPWLEdit()->ReplaceAndKeepSelection(L"xyz");
+  EXPECT_STREQ(L"AxyzDEFGHIJ", GetCPWLEdit()->GetText().c_str());
+  EXPECT_STREQ(L"xyz", GetCPWLEdit()->GetSelectedText().c_str());
+  EXPECT_EQ(GetCPWLEdit()->GetSelection(), std::make_pair(1, 4));
+
+  GetCPWLEdit()->SetSelection(4, 1);
+  GetCPWLEdit()->ReplaceAndKeepSelection(L"12");
+  EXPECT_STREQ(L"A12DEFGHIJ", GetCPWLEdit()->GetText().c_str());
+  EXPECT_STREQ(L"12", GetCPWLEdit()->GetSelectedText().c_str());
+  EXPECT_EQ(GetCPWLEdit()->GetSelection(), std::make_pair(1, 3));
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.cpp b/fpdfsdk/pwl/cpwl_edit_impl.cpp
index 2cc10cb..50e2c42 100644
--- a/fpdfsdk/pwl/cpwl_edit_impl.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_impl.cpp
@@ -1761,6 +1761,19 @@
   }
 }
 
+void CPWL_EditImpl::ReplaceAndKeepSelection(const WideString& text) {
+  AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, false));
+  ClearSelection();
+
+  // Select the inserted text.
+  CPVT_WordPlace caret_before_insert = m_wpCaret;
+  InsertText(text, FX_Charset::kDefault);
+  CPVT_WordPlace caret_after_insert = m_wpCaret;
+  m_SelState.Set(caret_before_insert, caret_after_insert);
+
+  AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, true));
+}
+
 void CPWL_EditImpl::ReplaceSelection(const WideString& text) {
   AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, false));
   ClearSelection();
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.h b/fpdfsdk/pwl/cpwl_edit_impl.h
index b4735c6..0b3bc76 100644
--- a/fpdfsdk/pwl/cpwl_edit_impl.h
+++ b/fpdfsdk/pwl/cpwl_edit_impl.h
@@ -99,6 +99,7 @@
   bool Delete();
   bool ClearSelection();
   bool InsertText(const WideString& sText, FX_Charset charset);
+  void ReplaceAndKeepSelection(const WideString& text);
   void ReplaceSelection(const WideString& text);
   bool Redo();
   bool Undo();
diff --git a/fpdfsdk/pwl/cpwl_wnd.cpp b/fpdfsdk/pwl/cpwl_wnd.cpp
index 9c585ed..755fcbb 100644
--- a/fpdfsdk/pwl/cpwl_wnd.cpp
+++ b/fpdfsdk/pwl/cpwl_wnd.cpp
@@ -345,6 +345,8 @@
   return WideString();
 }
 
+void CPWL_Wnd::ReplaceAndKeepSelection(const WideString& text) {}
+
 void CPWL_Wnd::ReplaceSelection(const WideString& text) {}
 
 bool CPWL_Wnd::SelectAllText() {
diff --git a/fpdfsdk/pwl/cpwl_wnd.h b/fpdfsdk/pwl/cpwl_wnd.h
index 262116a..b10b59a 100644
--- a/fpdfsdk/pwl/cpwl_wnd.h
+++ b/fpdfsdk/pwl/cpwl_wnd.h
@@ -169,6 +169,7 @@
 
   virtual WideString GetText();
   virtual WideString GetSelectedText();
+  virtual void ReplaceAndKeepSelection(const WideString& text);
   virtual void ReplaceSelection(const WideString& text);
   virtual bool SelectAllText();
 
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index dabb3d3..2bcf7f7 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -1560,12 +1560,35 @@
                      unsigned long buflen);
 
 /*
+ * Experimental API
+ * Function: FORM_ReplaceAndKeepSelection
+ *       Call this function to replace the selected text in a form
+ *       text field or user-editable form combobox text field with another
+ *       text string (which can be empty or non-empty). If there is no
+ *       selected text, this function will append the replacement text after
+ *       the current caret position. After the insertion, the inserted text
+ *       will be selected.
+ * Parameters:
+ *       hHandle     -   Handle to the form fill module, as returned by
+ *                       FPDFDOC_InitFormFillEnvironment().
+ *       page        -   Handle to the page, as Returned by FPDF_LoadPage().
+ *       wsText      -   The text to be inserted, in UTF-16LE format.
+ * Return Value:
+ *       None.
+ */
+FPDF_EXPORT void FPDF_CALLCONV
+FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,
+                             FPDF_PAGE page,
+                             FPDF_WIDESTRING wsText);
+
+/*
  * Function: FORM_ReplaceSelection
  *       Call this function to replace the selected text in a form
  *       text field or user-editable form combobox text field with another
  *       text string (which can be empty or non-empty). If there is no
  *       selected text, this function will append the replacement text after
- *       the current caret position.
+ *       the current caret position. After the insertion, the selection range
+ *       will be set to empty.
  * Parameters:
  *       hHandle     -   Handle to the form fill module, as returned by
  *                       FPDFDOC_InitFormFillEnvironment().