Add FORM_ReplaceSelection() and embedder tests.

This method replaces the selected text in a user-editable form text
area with another text string (which can be empty or non-empty). If
there is no selected text, FORM_ReplaceSelection() will append the
replacement text after the current caret position.

BUG=chromium:59266

Change-Id: I76448ef757d107888c33ebd5656457ebac93b952
Reviewed-on: https://pdfium-review.googlesource.com/8812
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Diana Gage <drgage@google.com>
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index fd77a73..a1ac14c 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -81,8 +81,10 @@
   return GetAnnotHandler(pAnnot)->GetSelectedText(pAnnot);
 }
 
-void CPDFSDK_AnnotHandlerMgr::Annot_DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
-  GetAnnotHandler(pAnnot)->DeleteSelectedText(pAnnot);
+void CPDFSDK_AnnotHandlerMgr::Annot_ReplaceSelection(
+    CPDFSDK_Annot* pAnnot,
+    const CFX_WideString& text) {
+  GetAnnotHandler(pAnnot)->ReplaceSelection(pAnnot, text);
 }
 
 IPDFSDK_AnnotHandler* CPDFSDK_AnnotHandlerMgr::GetAnnotHandler(
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.h b/fpdfsdk/cpdfsdk_annothandlermgr.h
index 93c552b..96765e5 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -44,7 +44,8 @@
   void Annot_OnLoad(CPDFSDK_Annot* pAnnot);
 
   CFX_WideString Annot_GetSelectedText(CPDFSDK_Annot* pAnnot);
-  void Annot_DeleteSelectedText(CPDFSDK_Annot* pAnnot);
+  void Annot_ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                              const CFX_WideString& text);
 
   IPDFSDK_AnnotHandler* GetAnnotHandler(CPDFSDK_Annot* pAnnot) const;
   void Annot_OnDraw(CPDFSDK_PageView* pPageView,
diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp
index cf09d2b..029df85 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -197,7 +197,8 @@
   return CFX_WideString();
 }
 
-void CPDFSDK_BAAnnotHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {}
+void CPDFSDK_BAAnnotHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                              const CFX_WideString& text) {}
 
 bool CPDFSDK_BAAnnotHandler::HitTest(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot,
diff --git a/fpdfsdk/cpdfsdk_baannothandler.h b/fpdfsdk/cpdfsdk_baannothandler.h
index 7db9a4d..86f7b93 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -38,7 +38,8 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
-  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                        const CFX_WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 84a60fa..209e8de 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -253,11 +253,11 @@
   return CFX_WideString();
 }
 
-void CPDFSDK_PageView::DeleteSelectedText() {
+void CPDFSDK_PageView::ReplaceSelection(const CFX_WideString& text) {
   if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
     CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
         m_pFormFillEnv->GetAnnotHandlerMgr();
-    pAnnotHandlerMgr->Annot_DeleteSelectedText(pAnnot);
+    pAnnotHandlerMgr->Annot_ReplaceSelection(pAnnot, text);
   }
 }
 
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index d4b7721..c525bfc 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -61,7 +61,7 @@
   }
 
   CFX_WideString GetSelectedText();
-  void DeleteSelectedText();
+  void ReplaceSelection(const CFX_WideString& text);
 
   bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag);
   bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag);
diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp
index 1c802a3..f5cd802 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -287,9 +287,10 @@
   return CFX_WideString();
 }
 
-void CPDFSDK_WidgetHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+void CPDFSDK_WidgetHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                             const CFX_WideString& text) {
   if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
-    m_pFormFiller->DeleteSelectedText(pAnnot);
+    m_pFormFiller->ReplaceSelection(pAnnot, text);
 }
 
 bool CPDFSDK_WidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
diff --git a/fpdfsdk/cpdfsdk_widgethandler.h b/fpdfsdk/cpdfsdk_widgethandler.h
index 2d33ff5..60bfd83 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -39,7 +39,8 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
-  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                        const CFX_WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
index 746d1ca..e7bf702 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -97,16 +97,17 @@
   return rcWidget;
 }
 
-// TODO(crbug.com/62400): Implement so selected text can be obtained from XFA
+// TODO(bug 840): Implement so selected text can be obtained from XFA
 // fields.
 CFX_WideString CPDFSDK_XFAWidgetHandler::GetSelectedText(
     CPDFSDK_Annot* pAnnot) {
   return CFX_WideString();
 }
 
-// TODO(crbug.com/62400): Implement so selected text can be deleted from XFA
+// TODO(bug 840): Implement so text can be inserted into and deleted from XFA
 // fields.
-void CPDFSDK_XFAWidgetHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {}
+void CPDFSDK_XFAWidgetHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                                const CFX_WideString& text) {}
 
 bool CPDFSDK_XFAWidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                        CPDFSDK_Annot* pAnnot,
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.h b/fpdfsdk/cpdfsdk_xfawidgethandler.h
index 3d06948..26e991d 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.h
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h
@@ -34,7 +34,8 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
-  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                        const CFX_WideString& text) override;
   bool HitTest(CPDFSDK_PageView* pPageView,
                CPDFSDK_Annot* pAnnot,
                const CFX_PointF& point) override;
diff --git a/fpdfsdk/formfiller/cffl_formfiller.cpp b/fpdfsdk/formfiller/cffl_formfiller.cpp
index a37a750..e0af895 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -245,7 +245,8 @@
   return pWnd ? pWnd->GetSelectedText() : CFX_WideString();
 }
 
-void CFFL_FormFiller::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+void CFFL_FormFiller::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                       const CFX_WideString& text) {
   if (!IsValid())
     return;
 
@@ -256,7 +257,7 @@
   if (!pWnd)
     return;
 
-  pWnd->DeleteSelectedText();
+  pWnd->ReplaceSelection(text);
 }
 
 void CFFL_FormFiller::SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag) {
diff --git a/fpdfsdk/formfiller/cffl_formfiller.h b/fpdfsdk/formfiller/cffl_formfiller.h
index 96b7a69..4769716 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -75,7 +75,7 @@
   virtual bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags);
 
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
-  void DeleteSelectedText(CPDFSDK_Annot* pAnnot);
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const CFX_WideString& text);
 
   void SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag);
   void KillFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag);
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index 24bfd3c..6d25040 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -523,13 +523,14 @@
   return pFormFiller ? pFormFiller->GetSelectedText(pAnnot) : CFX_WideString();
 }
 
-void CFFL_InteractiveFormFiller::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+void CFFL_InteractiveFormFiller::ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                                  const CFX_WideString& text) {
   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
   if (!pFormFiller)
     return;
 
-  pFormFiller->DeleteSelectedText(pAnnot);
+  pFormFiller->ReplaceSelection(pAnnot, text);
 }
 
 void CFFL_InteractiveFormFiller::UnRegisterFormFiller(CPDFSDK_Annot* pAnnot) {
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index 17e9407..b71f3a6 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -84,7 +84,7 @@
   void RemoveFormFiller(CPDFSDK_Annot* pAnnot);
 
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
-  void DeleteSelectedText(CPDFSDK_Annot* pAnnot);
+  void ReplaceSelection(CPDFSDK_Annot* pAnnot, const CFX_WideString& text);
 
   static bool IsVisible(CPDFSDK_Widget* pWidget);
   static bool IsReadOnly(CPDFSDK_Widget* pWidget);
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index e541b81..7f4e3df 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -383,12 +383,17 @@
   return form_text_len;
 }
 
-DLLEXPORT void STDCALL FORM_DeleteSelectedText(FPDF_FORMHANDLE hHandle,
-                                               FPDF_PAGE page) {
+DLLEXPORT void STDCALL FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,
+                                             FPDF_PAGE page,
+                                             FPDF_WIDESTRING wsText) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
   if (!pPageView)
     return;
-  pPageView->DeleteSelectedText();
+
+  FX_STRSIZE len = CFX_WideString::WStringLength(wsText);
+  CFX_WideString wide_str_text = CFX_WideString::FromUTF16LE(wsText, len);
+
+  pPageView->ReplaceSelection(wide_str_text);
 }
 
 DLLEXPORT FPDF_BOOL STDCALL FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) {
diff --git a/fpdfsdk/fpdfformfill_embeddertest.cpp b/fpdfsdk/fpdfformfill_embeddertest.cpp
index 1505fdc..13d5f08 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -656,7 +656,8 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
+
   SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
   CheckSelection(page, CFX_WideString());
 
@@ -676,7 +677,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
   CheckSelection(page, CFX_WideString(L"ABCJKL"));
 
@@ -696,7 +697,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
   CheckSelection(page, CFX_WideString(L"EFGHIJKL"));
 
@@ -716,7 +717,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
   CheckSelection(page, CFX_WideString(L"ABCDEFGH"));
 
@@ -734,7 +735,7 @@
   CheckSelection(page, CFX_WideString());
 
   // Test that attempt to delete empty text selection has no effect.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
   CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
 
@@ -754,7 +755,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithMouse(page, 178.0, 102.0, 62.0);
   CheckSelection(page, CFX_WideString());
 
@@ -774,7 +775,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithMouse(page, 178.0, 102.0, 62.0);
   CheckSelection(page, CFX_WideString(L"ABCIJ"));
 
@@ -794,7 +795,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithMouse(page, 178.0, 102.0, 62.0);
   CheckSelection(page, CFX_WideString(L"EFGHIJ"));
 
@@ -814,7 +815,7 @@
 
   // Test deleting current text selection. Select what remains after deletion to
   // check that remaining text is as expected.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithMouse(page, 178.0, 102.0, 62.0);
   CheckSelection(page, CFX_WideString(L"ABCDEF"));
 
@@ -832,9 +833,635 @@
   CheckSelection(page, CFX_WideString());
 
   // Test that attempt to delete empty text selection has no effect.
-  FORM_DeleteSelectedText(form_handle(), page);
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
   SelectTextWithMouse(page, 178.0, 102.0, 62.0);
   CheckSelection(page, CFX_WideString(L"ABCDEFGHIJ"));
 
   UnloadPage(page);
 }
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInEmptyTextField) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  ClickOnFormFieldAtPoint(page, 120.0, 120.0);
+
+  // Test inserting text into empty text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"Hello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedTextFieldLeft) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 8, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Click on the leftmost part of the text field.
+  ClickOnFormFieldAtPoint(page, 102.0, 115.5);
+
+  // Test inserting text in front of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"HelloABCDEFGH"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedTextFieldMiddle) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 8, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Click on the middle of the text field.
+  ClickOnFormFieldAtPoint(page, 134.0, 115.5);
+
+  // Test inserting text in the middle of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDHelloEFGH"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedTextFieldRight) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 8, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Click on the rightmost part of the text field.
+  ClickOnFormFieldAtPoint(page, 166.0, 115.5);
+
+  // Test inserting text behind existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHHello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldWhole) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select entire string in text field.
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 195.0, 115.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"Hello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldLeft) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select left portion of string in text field.
+  SelectTextWithKeyboard(page, 6, FWL_VKEY_Left, 148.0, 115.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEF"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"HelloGHIJKL"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldMiddle) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select middle portion of string in text field.
+  SelectTextWithKeyboard(page, 6, FWL_VKEY_Left, 171.0, 115.0);
+  CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCHelloJKL"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldRight) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select right portion of string in text field.
+  SelectTextWithKeyboard(page, 6, FWL_VKEY_Left, 195.0, 115.0);
+  CheckSelection(page, CFX_WideString(L"GHIJKL"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDEFHello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInEmptyEditableComboBox) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  ClickOnFormFieldAtPoint(page, 102.0, 62.0);
+
+  // Test inserting text into empty user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"Hello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedEditableComboBoxLeft) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 6, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Click on the leftmost part of the user-editable combobox.
+  ClickOnFormFieldAtPoint(page, 102.0, 62.0);
+
+  // Test inserting text in front of existing text in user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"HelloABCDEF"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedEditableComboBoxMiddle) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 6, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Click on the middle of the user-editable combobox.
+  ClickOnFormFieldAtPoint(page, 126.0, 62.0);
+
+  // Test inserting text in the middle of existing text in user-editable
+  // combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCHelloDEF"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedEditableComboBoxRight) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 6, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Click on the rightmost part of the user-editable combobox.
+  ClickOnFormFieldAtPoint(page, 150.0, 62.0);
+
+  // Test inserting text behind existing text in user-editable combobox.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEFHello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxWhole) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Select entire string in user-editable combobox.
+  SelectTextWithKeyboard(page, 10, FWL_VKEY_Left, 183.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJ"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"Hello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxLeft) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Select left portion of string in user-editable combobox.
+  SelectTextWithKeyboard(page, 5, FWL_VKEY_Left, 142.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCDE"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"HelloFGHIJ"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxMiddle) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Select middle portion of string in user-editable combobox.
+  SelectTextWithKeyboard(page, 5, FWL_VKEY_Left, 167.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"DEFGH"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCHelloIJ"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxRight) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+
+  // Select right portion of string in user-editable combobox.
+  SelectTextWithKeyboard(page, 5, FWL_VKEY_Left, 183.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"FGHIJ"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of user-editable combobox text field to check that
+  // insertion worked as expected.
+  SelectTextWithMouse(page, 183.0, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEHello"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInEmptyCharLimitTextFieldOverflow) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Click on the textfield.
+  ClickOnFormFieldAtPoint(page, 195.0, 60.0);
+
+  // Delete pre-filled contents of text field with char limit.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Elephant"));
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
+
+  // Test inserting text into now empty text field so text to be inserted
+  // exceeds the char limit and is cut off.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Hippopotam"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInEmptyCharLimitTextFieldFit) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Click on the textfield.
+  ClickOnFormFieldAtPoint(page, 195.0, 60.0);
+
+  // Delete pre-filled contents of text field with char limit.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Elephant"));
+  FORM_ReplaceSelection(form_handle(), page, nullptr);
+
+  // Test inserting text into now empty text field so text to be inserted
+  // exceeds the char limit and is cut off.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Zebra");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Zebra"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedCharLimitTextFieldLeft) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Click on the leftmost part of the text field.
+  ClickOnFormFieldAtPoint(page, 102.0, 60.0);
+
+  // Test inserting text in front of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"HiElephant"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextInPopulatedCharLimitTextFieldMiddle) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 8, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Click on the middle of the text field.
+  ClickOnFormFieldAtPoint(page, 134.0, 60.0);
+
+  // Test inserting text in the middle of existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"ElephHiant"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, InsertTextInPopulatedCharLimitTextFieldRight) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 8, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Click on the rightmost part of the text field.
+  ClickOnFormFieldAtPoint(page, 166.0, 60.0);
+
+  // Test inserting text behind existing text in text field.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"ElephantHi"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldWhole) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select entire string in text field.
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 195.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Elephant"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Hippopotam"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldLeft) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select left portion of string in text field.
+  SelectTextWithKeyboard(page, 4, FWL_VKEY_Left, 122.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Elep"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"Hippophant"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldMiddle) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select middle portion of string in text field.
+  SelectTextWithKeyboard(page, 4, FWL_VKEY_Left, 136.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"epha"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"ElHippopnt"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldRight) {
+  // Open file with form text field with a character limit of 10.
+  EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+
+  // Select right portion of string in text field.
+  SelectTextWithKeyboard(page, 4, FWL_VKEY_Left, 152.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"hant"));
+
+  // Test replacing text selection with text to be inserted.
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text_to_insert =
+      GetFPDFWideString(L"Hippopotamus");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Select entire contents of text field to check that insertion worked
+  // as expected.
+  SelectTextWithMouse(page, 195.0, 102.0, 60.0);
+  CheckSelection(page, CFX_WideString(L"ElepHippop"));
+
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 95a0175..7d42be8 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -182,7 +182,7 @@
     CHK(FORM_OnKeyUp);
     CHK(FORM_OnChar);
     CHK(FORM_GetSelectedText);
-    CHK(FORM_DeleteSelectedText);
+    CHK(FORM_ReplaceSelection);
     CHK(FORM_ForceToKillFocus);
     CHK(FPDFPage_HasFormFieldAtPoint);
     CHK(FPDFPage_FormFieldZOrderAtPoint);
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 5340978..3a35cdc 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -37,7 +37,8 @@
   virtual CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot) = 0;
   virtual CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) = 0;
-  virtual void DeleteSelectedText(CPDFSDK_Annot* pAnnot) = 0;
+  virtual void ReplaceSelection(CPDFSDK_Annot* pAnnot,
+                                const CFX_WideString& text) = 0;
   virtual bool HitTest(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot* pAnnot,
                        const CFX_PointF& point) = 0;
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
index 9514e55..49254b8 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
@@ -184,9 +184,9 @@
   return CFX_WideString();
 }
 
-void CPWL_ComboBox::DeleteSelectedText() {
+void CPWL_ComboBox::ReplaceSelection(const CFX_WideString& text) {
   if (m_pEdit)
-    m_pEdit->DeleteSelectedText();
+    m_pEdit->ReplaceSelection(text);
 }
 
 CFX_WideString CPWL_ComboBox::GetText() const {
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
index a50c4ce..81e4256 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.h
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
@@ -63,7 +63,7 @@
   void SetFocus() override;
   void KillFocus() override;
   CFX_WideString GetSelectedText() override;
-  void DeleteSelectedText() override;
+  void ReplaceSelection(const CFX_WideString& text) override;
 
   void SetFillerNotify(IPWL_Filler_Notify* pNotify);
 
diff --git a/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp b/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp
index 30fe32b..308ee4a 100644
--- a/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp
+++ b/fpdfsdk/pwl/cpwl_combo_box_embeddertest.cpp
@@ -211,7 +211,7 @@
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLComboBox()->GetSelectedText().c_str());
 
-  GetCPWLComboBox()->DeleteSelectedText();
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString());
   EXPECT_TRUE(GetCPWLComboBox()->GetText().IsEmpty());
 }
 
@@ -222,7 +222,7 @@
   GetCPWLComboBox()->SetEditSelection(12, 23);
   EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLComboBox()->GetSelectedText().c_str());
 
-  GetCPWLComboBox()->DeleteSelectedText();
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLComboBox()->GetText().c_str());
 }
@@ -234,7 +234,7 @@
   GetCPWLComboBox()->SetEditSelection(0, 5);
   EXPECT_STREQ(L"ABCDE", GetCPWLComboBox()->GetSelectedText().c_str());
 
-  GetCPWLComboBox()->DeleteSelectedText();
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLComboBox()->GetText().c_str());
 }
@@ -246,7 +246,7 @@
   GetCPWLComboBox()->SetEditSelection(45, 50);
   EXPECT_STREQ(L"nopqr", GetCPWLComboBox()->GetSelectedText().c_str());
 
-  GetCPWLComboBox()->DeleteSelectedText();
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
                GetCPWLComboBox()->GetText().c_str());
 }
@@ -255,7 +255,94 @@
   FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
   TypeTextIntoTextField(50);
 
-  GetCPWLComboBox()->DeleteSelectedText();
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLComboBox()->GetText().c_str());
 }
+
+TEST_F(CPWLComboBoxEditEmbeddertest, InsertTextInEmptyEditableComboBox) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"Hello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to beginning of user-editable combobox text field.
+  EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotUserEditable(),
+                                             FWL_VKEY_Home, 0));
+
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"HelloABCDEFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to middle of user-editable combobox text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotUserEditable(),
+                                               FWL_VKEY_Left, 0));
+  }
+
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEHelloFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextInPopulatedEditableComboBoxRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEFGHIJHello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"Hello", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"HelloFGHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(2, 7);
+  EXPECT_STREQ(L"CDEFG", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABHelloHIJ", GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedEditableComboBoxRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  TypeTextIntoTextField(10);
+
+  GetCPWLComboBox()->SetEditSelection(5, 10);
+  EXPECT_STREQ(L"FGHIJ", GetCPWLComboBox()->GetSelectedText().c_str());
+  GetCPWLComboBox()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEHello", GetCPWLComboBox()->GetText().c_str());
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.cpp b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
index a852cb6..1a7b0e4 100644
--- a/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
@@ -59,9 +59,12 @@
   return CFX_WideString();
 }
 
-void CPWL_EditCtrl::DeleteSelectedText() {
-  if (m_pEdit)
-    m_pEdit->ClearSelection();
+void CPWL_EditCtrl::ReplaceSelection(const CFX_WideString& text) {
+  if (!m_pEdit)
+    return;
+
+  m_pEdit->ClearSelection();
+  m_pEdit->InsertText(text, FX_CHARSET_Default);
 }
 
 void CPWL_EditCtrl::RePosChildWnd() {
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.h b/fpdfsdk/pwl/cpwl_edit_ctrl.h
index 4fb86fa..03dc4be 100644
--- a/fpdfsdk/pwl/cpwl_edit_ctrl.h
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.h
@@ -61,7 +61,7 @@
   float GetFontSize() const override;
   void SetCursor() override;
   CFX_WideString GetSelectedText() override;
-  void DeleteSelectedText() override;
+  void ReplaceSelection(const CFX_WideString& text) override;
 
   void SetCaret(bool bVisible,
                 const CFX_PointF& ptHead,
diff --git a/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
index 98cc44a..34569b2 100644
--- a/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_embeddertest.cpp
@@ -24,35 +24,44 @@
   }
 
   void CreateAndInitializeFormPDF() {
-    EXPECT_TRUE(OpenDocument("text_form.pdf"));
+    EXPECT_TRUE(OpenDocument("text_form_multiple.pdf"));
     m_page = LoadPage(0);
     ASSERT_TRUE(m_page);
 
-    CPDFSDK_FormFillEnvironment* pFormFillEnv =
-        static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
+    m_pFormFillEnv = static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
+    CBA_AnnotIterator iter(m_pFormFillEnv->GetPageView(0),
+                           CPDF_Annot::Subtype::WIDGET);
+    // Normal text field.
+    m_pAnnot = iter.GetFirstAnnot();
+    ASSERT_TRUE(m_pAnnot);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, m_pAnnot->GetAnnotSubtype());
 
-    {
-      CBA_AnnotIterator iter(pFormFillEnv->GetPageView(0),
-                             CPDF_Annot::Subtype::WIDGET);
-      m_pAnnot = iter.GetFirstAnnot();
-      CPDFSDK_Annot* pLastAnnot = iter.GetLastAnnot();
-      ASSERT_EQ(m_pAnnot, pLastAnnot);
-      ASSERT_TRUE(m_pAnnot);
-      ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, m_pAnnot->GetAnnotSubtype());
-    }
+    // Read-only text field.
+    CPDFSDK_Annot* pAnnotReadOnly = iter.GetNextAnnot(m_pAnnot);
 
+    // Pre-filled text field with char limit of 10.
+    m_pAnnotCharLimit = iter.GetNextAnnot(pAnnotReadOnly);
+    ASSERT_TRUE(m_pAnnotCharLimit);
+    ASSERT_EQ(CPDF_Annot::Subtype::WIDGET,
+              m_pAnnotCharLimit->GetAnnotSubtype());
+    CPDFSDK_Annot* pLastAnnot = iter.GetLastAnnot();
+    ASSERT_EQ(m_pAnnotCharLimit, pLastAnnot);
+  }
+
+  void FormFillerAndWindowSetup(CPDFSDK_Annot* pAnnotTextField) {
     CFFL_InteractiveFormFiller* pInteractiveFormFiller =
-        pFormFillEnv->GetInteractiveFormFiller();
+        m_pFormFillEnv->GetInteractiveFormFiller();
     {
-      CPDFSDK_Annot::ObservedPtr pObserved(m_pAnnot);
+      CPDFSDK_Annot::ObservedPtr pObserved(pAnnotTextField);
       EXPECT_TRUE(pInteractiveFormFiller->OnSetFocus(&pObserved, 0));
     }
 
-    m_pFormFiller = pInteractiveFormFiller->GetFormFiller(m_pAnnot, false);
+    m_pFormFiller =
+        pInteractiveFormFiller->GetFormFiller(pAnnotTextField, false);
     ASSERT_TRUE(m_pFormFiller);
 
     CPWL_Wnd* pWindow =
-        m_pFormFiller->GetPDFWindow(pFormFillEnv->GetPageView(0), false);
+        m_pFormFiller->GetPDFWindow(m_pFormFillEnv->GetPageView(0), false);
     ASSERT_TRUE(pWindow);
     ASSERT_EQ(PWL_CLASSNAME_EDIT, pWindow->GetClassName());
 
@@ -70,15 +79,19 @@
   CPWL_Edit* GetCPWLEdit() { return m_pEdit; }
   CFFL_FormFiller* GetCFFLFormFiller() { return m_pFormFiller; }
   CPDFSDK_Annot* GetCPDFSDKAnnot() { return m_pAnnot; }
+  CPDFSDK_Annot* GetCPDFSDKAnnotCharLimit() { return m_pAnnotCharLimit; }
 
  private:
   FPDF_PAGE m_page;
   CPWL_Edit* m_pEdit;
   CFFL_FormFiller* m_pFormFiller;
   CPDFSDK_Annot* m_pAnnot;
+  CPDFSDK_Annot* m_pAnnotCharLimit;
+  CPDFSDK_FormFillEnvironment* m_pFormFillEnv;
 };
 
 TEST_F(CPWLEditEmbeddertest, TypeText) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
   EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'a', 0));
   EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'b', 0));
@@ -88,6 +101,7 @@
 }
 
 TEST_F(CPWLEditEmbeddertest, GetSelectedTextEmptyAndBasic) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   // Attempt to set selection before text has been typed to test that
   // selection is identified as empty.
   //
@@ -104,6 +118,7 @@
 }
 
 TEST_F(CPWLEditEmbeddertest, GetSelectedTextFragments) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
   GetCPWLEdit()->SetSelection(0, 0);
@@ -133,53 +148,226 @@
 }
 
 TEST_F(CPWLEditEmbeddertest, DeleteEntireTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
   GetCPWLEdit()->SetSelection(0, -1);
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLEdit()->GetSelectedText().c_str());
 
-  GetCPWLEdit()->DeleteSelectedText();
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
   EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
 }
 
 TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
   GetCPWLEdit()->SetSelection(12, 23);
   EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
 
-  GetCPWLEdit()->DeleteSelectedText();
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLEdit()->GetText().c_str());
 }
 
 TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
   GetCPWLEdit()->SetSelection(0, 5);
   EXPECT_STREQ(L"ABCDE", GetCPWLEdit()->GetSelectedText().c_str());
 
-  GetCPWLEdit()->DeleteSelectedText();
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLEdit()->GetText().c_str());
 }
 
 TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
   GetCPWLEdit()->SetSelection(45, 50);
   EXPECT_STREQ(L"nopqr", GetCPWLEdit()->GetSelectedText().c_str());
 
-  GetCPWLEdit()->DeleteSelectedText();
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
                GetCPWLEdit()->GetText().c_str());
 }
 
 TEST_F(CPWLEditEmbeddertest, DeleteEmptyTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
   TypeTextIntoTextField(50);
 
-  GetCPWLEdit()->DeleteSelectedText();
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
   EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
                GetCPWLEdit()->GetText().c_str());
 }
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyTextField) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"Hello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to beginning of text field.
+  EXPECT_TRUE(
+      GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnot(), FWL_VKEY_Home, 0));
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"HelloABCDEFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  // Move cursor to middle of text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnot(), FWL_VKEY_Left, 0));
+  }
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEHelloFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEFGHIJHello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJ", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"Hello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"HelloFGHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(2, 7);
+  EXPECT_STREQ(L"CDEFG", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABHelloHIJ", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnot());
+  TypeTextIntoTextField(10);
+
+  GetCPWLEdit()->SetSelection(5, 10);
+  EXPECT_STREQ(L"FGHIJ", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hello"));
+  EXPECT_STREQ(L"ABCDEHello", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyCharLimitTextFieldOverflow) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"Hippopotam", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInEmptyCharLimitTextFieldFit) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString());
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Zebra"));
+  EXPECT_STREQ(L"Zebra", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"HiElephant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  // Move cursor to middle of text field.
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotCharLimit(),
+                                               FWL_VKEY_Right, 0));
+  }
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"ElephHiant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, InsertTextInPopulatedCharLimitTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  // Move cursor to end of text field.
+  EXPECT_TRUE(GetCFFLFormFiller()->OnKeyDown(GetCPDFSDKAnnotCharLimit(),
+                                             FWL_VKEY_End, 0));
+
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"ElephantHi", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldWhole) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"Elephant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"Hippopotam", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(0, 4);
+  EXPECT_STREQ(L"Elep", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"Hippophant", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(2, 6);
+  EXPECT_STREQ(L"epha", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"ElHippopnt", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest,
+       InsertTextAndReplaceSelectionInPopulatedCharLimitTextFieldRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotCharLimit());
+  GetCPWLEdit()->SetSelection(4, 8);
+  EXPECT_STREQ(L"hant", GetCPWLEdit()->GetSelectedText().c_str());
+  GetCPWLEdit()->ReplaceSelection(CFX_WideString(L"Hippopotamus"));
+  EXPECT_STREQ(L"ElepHippop", GetCPWLEdit()->GetText().c_str());
+}
diff --git a/fpdfsdk/pwl/cpwl_wnd.cpp b/fpdfsdk/pwl/cpwl_wnd.cpp
index 2269162..c7bf23c 100644
--- a/fpdfsdk/pwl/cpwl_wnd.cpp
+++ b/fpdfsdk/pwl/cpwl_wnd.cpp
@@ -369,7 +369,7 @@
   return CFX_WideString();
 }
 
-void CPWL_Wnd::DeleteSelectedText() {}
+void CPWL_Wnd::ReplaceSelection(const CFX_WideString& text) {}
 
 bool CPWL_Wnd::OnMouseWheel(short zDelta,
                             const CFX_PointF& point,
diff --git a/fpdfsdk/pwl/cpwl_wnd.h b/fpdfsdk/pwl/cpwl_wnd.h
index 7c93216..15487a3 100644
--- a/fpdfsdk/pwl/cpwl_wnd.h
+++ b/fpdfsdk/pwl/cpwl_wnd.h
@@ -202,7 +202,7 @@
   virtual float GetFontSize() const;
 
   virtual CFX_WideString GetSelectedText();
-  virtual void DeleteSelectedText();
+  virtual void ReplaceSelection(const CFX_WideString& text);
   virtual CFX_FloatRect GetFocusRect() const;
   virtual CFX_FloatRect GetClientRect() const;
 
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index 83a4e58..617bc34 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -1378,20 +1378,24 @@
                                                      unsigned long buflen);
 
 /**
- * Function: FORM_DeleteSelectedText
- *          You can call this function to delete the current text selection in
- *          a form text field or user-editable form combobox text field. If
- *          there is no selected text, this function does nothing.
+ * Function: FORM_ReplaceSelection
+ *          You can 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.
  * Parameters:
  *          hHandle     -   Handle to the form fill module. Returned by
  *                          FPDFDOC_InitFormFillEnvironment.
  *          page        -   Handle to the page. Returned by FPDF_LoadPage
  *                          function.
+ *          wsText      -   The text to be inserted, in UTF-16LE format.
  * Return Value:
  *          None.
  **/
-DLLEXPORT void STDCALL FORM_DeleteSelectedText(FPDF_FORMHANDLE hHandle,
-                                               FPDF_PAGE page);
+DLLEXPORT void STDCALL FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,
+                                             FPDF_PAGE page,
+                                             FPDF_WIDESTRING wsText);
 
 /**
  * Function: FORM_ForceToKillFocus.
diff --git a/testing/resources/text_form_multiple.in b/testing/resources/text_form_multiple.in
index 43919eb..576e155 100644
--- a/testing/resources/text_form_multiple.in
+++ b/testing/resources/text_form_multiple.in
@@ -3,7 +3,7 @@
 <<
   /Type /Catalog
   /Pages 2 0 R
-  /AcroForm << /Fields [ 4 0 R 9 0 R ] /DR 5 0 R >>
+  /AcroForm << /Fields [ 4 0 R 9 0 R 10 0 R ] /DR 5 0 R >>
 >>
 endobj
 {{object 2 0}}
@@ -16,7 +16,7 @@
   /Resources 5 0 R
   /MediaBox [ 0 0 300 300 ]
   /Contents 8 0 R
-  /Annots [ 4 0 R 9 0 R ]
+  /Annots [ 4 0 R 9 0 R 10 0 R ]
 >>
 endobj
 {{object 4 0}}
@@ -63,6 +63,18 @@
   /Subtype /Widget
 >>
 endobj
+{{object 10 0}}
+<<
+  /Type /Annot
+  /FT /Tx
+  /T (CharLimit)
+  /MaxLen 10
+  /DA (0 0 0 rg /F1 12 Tf)
+  /V (Elephant)
+  /Rect [ 100 50 200 75 ]
+  /Subtype /Widget
+>>
+endobj
 {{xref}}
 {{trailer}}
 {{startxref}}
diff --git a/testing/resources/text_form_multiple.pdf b/testing/resources/text_form_multiple.pdf
index 6b14cef..172ab5e 100644
--- a/testing/resources/text_form_multiple.pdf
+++ b/testing/resources/text_form_multiple.pdf
@@ -4,7 +4,7 @@
 <<
   /Type /Catalog
   /Pages 2 0 R
-  /AcroForm << /Fields [ 4 0 R 9 0 R ] /DR 5 0 R >>
+  /AcroForm << /Fields [ 4 0 R 9 0 R 10 0 R ] /DR 5 0 R >>
 >>
 endobj
 2 0 obj
@@ -17,7 +17,7 @@
   /Resources 5 0 R
   /MediaBox [ 0 0 300 300 ]
   /Contents 8 0 R
-  /Annots [ 4 0 R 9 0 R ]
+  /Annots [ 4 0 R 9 0 R 10 0 R ]
 >>
 endobj
 4 0 obj
@@ -64,19 +64,32 @@
   /Subtype /Widget
 >>
 endobj
+10 0 obj
+<<
+  /Type /Annot
+  /FT /Tx
+  /T (CharLimit)
+  /MaxLen 10
+  /DA (0 0 0 rg /F1 12 Tf)
+  /V (Elephant)
+  /Rect [ 100 50 200 75 ]
+  /Subtype /Widget
+>>
+endobj
 xref
-0 10
+0 11
 0000000000 65535 f 
 0000000015 00000 n 
-0000000120 00000 n 
-0000000179 00000 n 
-0000000321 00000 n 
-0000000457 00000 n 
-0000000490 00000 n 
-0000000521 00000 n 
-0000000597 00000 n 
-0000000697 00000 n 
-trailer<< /Root 1 0 R /Size 10 >>
+0000000127 00000 n 
+0000000186 00000 n 
+0000000335 00000 n 
+0000000471 00000 n 
+0000000504 00000 n 
+0000000535 00000 n 
+0000000611 00000 n 
+0000000711 00000 n 
+0000000855 00000 n 
+trailer<< /Root 1 0 R /Size 11 >>
 startxref
-841
+1020
 %%EOF