Add FORM_DeleteSelectedText() and embedder tests.

This method deletes the current text selection in a form text field or
user-editable form combobox text field. If there is no selection, this
method does nothing.

BUG=chromium:59266

Change-Id: I3229ffad990c62beac1cf769cd366458b9ee5daa
Reviewed-on: https://pdfium-review.googlesource.com/8370
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 9e649f6..fd77a73 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -81,6 +81,10 @@
   return GetAnnotHandler(pAnnot)->GetSelectedText(pAnnot);
 }
 
+void CPDFSDK_AnnotHandlerMgr::Annot_DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+  GetAnnotHandler(pAnnot)->DeleteSelectedText(pAnnot);
+}
+
 IPDFSDK_AnnotHandler* CPDFSDK_AnnotHandlerMgr::GetAnnotHandler(
     CPDFSDK_Annot* pAnnot) const {
   return GetAnnotHandler(pAnnot->GetAnnotSubtype());
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.h b/fpdfsdk/cpdfsdk_annothandlermgr.h
index ff2556f..93c552b 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -44,6 +44,7 @@
   void Annot_OnLoad(CPDFSDK_Annot* pAnnot);
 
   CFX_WideString Annot_GetSelectedText(CPDFSDK_Annot* pAnnot);
+  void Annot_DeleteSelectedText(CPDFSDK_Annot* pAnnot);
 
   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 4984ee9..cf09d2b 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -197,6 +197,8 @@
   return CFX_WideString();
 }
 
+void CPDFSDK_BAAnnotHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {}
+
 bool CPDFSDK_BAAnnotHandler::HitTest(CPDFSDK_PageView* pPageView,
                                      CPDFSDK_Annot* pAnnot,
                                      const CFX_PointF& point) {
diff --git a/fpdfsdk/cpdfsdk_baannothandler.h b/fpdfsdk/cpdfsdk_baannothandler.h
index 2af2f3e..7db9a4d 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -38,6 +38,7 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) 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 06761a5..84a60fa 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -253,6 +253,14 @@
   return CFX_WideString();
 }
 
+void CPDFSDK_PageView::DeleteSelectedText() {
+  if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
+    CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
+        m_pFormFillEnv->GetAnnotHandlerMgr();
+    pAnnotHandlerMgr->Annot_DeleteSelectedText(pAnnot);
+  }
+}
+
 bool CPDFSDK_PageView::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
   CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
   if (!pAnnot) {
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index 9eebb6e..d4b7721 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -61,6 +61,7 @@
   }
 
   CFX_WideString GetSelectedText();
+  void DeleteSelectedText();
 
   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 d916567..1c802a3 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -287,6 +287,11 @@
   return CFX_WideString();
 }
 
+void CPDFSDK_WidgetHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+  if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
+    m_pFormFiller->DeleteSelectedText(pAnnot);
+}
+
 bool CPDFSDK_WidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                     CPDFSDK_Annot* pAnnot,
                                     const CFX_PointF& point) {
diff --git a/fpdfsdk/cpdfsdk_widgethandler.h b/fpdfsdk/cpdfsdk_widgethandler.h
index aac3619..2d33ff5 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -39,6 +39,7 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) 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 aa4c0f1..746d1ca 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -97,11 +97,17 @@
   return rcWidget;
 }
 
+// TODO(crbug.com/62400): 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
+// fields.
+void CPDFSDK_XFAWidgetHandler::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {}
+
 bool CPDFSDK_XFAWidgetHandler::HitTest(CPDFSDK_PageView* pPageView,
                                        CPDFSDK_Annot* pAnnot,
                                        const CFX_PointF& point) {
diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.h b/fpdfsdk/cpdfsdk_xfawidgethandler.h
index 65e5e45..3d06948 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.h
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h
@@ -34,6 +34,7 @@
   CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
                             CPDFSDK_Annot* pAnnot) override;
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
+  void DeleteSelectedText(CPDFSDK_Annot* pAnnot) 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 edbd671..a37a750 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -245,6 +245,20 @@
   return pWnd ? pWnd->GetSelectedText() : CFX_WideString();
 }
 
+void CFFL_FormFiller::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+  if (!IsValid())
+    return;
+
+  CPDFSDK_PageView* pPageView = GetCurPageView(true);
+  ASSERT(pPageView);
+
+  CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+  if (!pWnd)
+    return;
+
+  pWnd->DeleteSelectedText();
+}
+
 void CFFL_FormFiller::SetFocusForAnnot(CPDFSDK_Annot* pAnnot, uint32_t nFlag) {
   CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)pAnnot;
   UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
diff --git a/fpdfsdk/formfiller/cffl_formfiller.h b/fpdfsdk/formfiller/cffl_formfiller.h
index 3eedebe..96b7a69 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -75,6 +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 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 8a81f4c..24bfd3c 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -523,6 +523,15 @@
   return pFormFiller ? pFormFiller->GetSelectedText(pAnnot) : CFX_WideString();
 }
 
+void CFFL_InteractiveFormFiller::DeleteSelectedText(CPDFSDK_Annot* pAnnot) {
+  ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+  if (!pFormFiller)
+    return;
+
+  pFormFiller->DeleteSelectedText(pAnnot);
+}
+
 void CFFL_InteractiveFormFiller::UnRegisterFormFiller(CPDFSDK_Annot* pAnnot) {
   auto it = m_Maps.find(pAnnot);
   if (it == m_Maps.end())
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index fb141e1..744d522 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -84,6 +84,7 @@
   void RemoveFormFiller(CPDFSDK_Annot* pAnnot);
 
   CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
+  void DeleteSelectedText(CPDFSDK_Annot* pAnnot);
 
   static bool IsVisible(CPDFSDK_Widget* pWidget);
   static bool IsReadOnly(CPDFSDK_Widget* pWidget);
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index 24cd64e..627bd0a 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -383,6 +383,14 @@
   return form_text_len;
 }
 
+DLLEXPORT void STDCALL FORM_DeleteSelectedText(FPDF_FORMHANDLE hHandle,
+                                               FPDF_PAGE page) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  if (!pPageView)
+    return;
+  pPageView->DeleteSelectedText();
+}
+
 DLLEXPORT FPDF_BOOL STDCALL FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       HandleToCPDFSDKEnvironment(hHandle);
diff --git a/fpdfsdk/fpdfformfill_embeddertest.cpp b/fpdfsdk/fpdfformfill_embeddertest.cpp
index 7089927..d0fd6de 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -22,7 +22,7 @@
 
 class FPDFFormFillEmbeddertest : public EmbedderTest {
  protected:
-  void TypeTextIntoTextfield(FPDF_PAGE page,
+  void TypeTextIntoTextField(FPDF_PAGE page,
                              int num_chars,
                              int form_type,
                              double x,
@@ -380,10 +380,10 @@
   ASSERT_TRUE(page);
 
   // Test empty selection.
-  CheckSelection(page, CFX_WideString(L""));
+  CheckSelection(page, CFX_WideString());
 
   // Test basic selection.
-  TypeTextIntoTextfield(page, 3, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  TypeTextIntoTextField(page, 3, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
   SelectTextWithKeyboard(page, 3, FWL_VKEY_Left, 123.0, 115.5);
   CheckSelection(page, CFX_WideString(L"ABC"));
 
@@ -397,10 +397,10 @@
   ASSERT_TRUE(page);
 
   // Test empty selection.
-  CheckSelection(page, CFX_WideString(L""));
+  CheckSelection(page, CFX_WideString());
 
   // Test basic selection.
-  TypeTextIntoTextfield(page, 3, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  TypeTextIntoTextField(page, 3, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
   SelectTextWithMouse(page, 125.0, 102.0, 115.5);
   CheckSelection(page, CFX_WideString(L"ABC"));
 
@@ -413,7 +413,7 @@
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
 
-  TypeTextIntoTextfield(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
 
   // Test selecting first character in forward direction.
   SelectTextWithKeyboard(page, 1, FWL_VKEY_Right, 102.0, 115.5);
@@ -444,7 +444,7 @@
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
 
-  TypeTextIntoTextfield(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
 
   // Test selecting first character in forward direction.
   SelectTextWithMouse(page, 102.0, 106.0, 115.5);
@@ -476,7 +476,7 @@
   ASSERT_TRUE(page);
 
   // Test empty selection.
-  CheckSelection(page, CFX_WideString(L""));
+  CheckSelection(page, CFX_WideString());
 
   // Test basic selection of text within normal, non-editable combobox.
   // Click on normal combobox text field.
@@ -502,10 +502,10 @@
   ASSERT_TRUE(page);
 
   // Test empty selection.
-  CheckSelection(page, CFX_WideString(L""));
+  CheckSelection(page, CFX_WideString());
 
   // Test basic selection of text within user editable combobox using keyboard.
-  TypeTextIntoTextfield(page, 3, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  TypeTextIntoTextField(page, 3, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
   SelectTextWithKeyboard(page, 3, FWL_VKEY_Left, 128.0, 63.0);
   CheckSelection(page, CFX_WideString(L"ABC"));
 
@@ -524,10 +524,10 @@
   ASSERT_TRUE(page);
 
   // Test empty selection.
-  CheckSelection(page, CFX_WideString(L""));
+  CheckSelection(page, CFX_WideString());
 
   // Test basic selection of text within user editable combobox using mouse.
-  TypeTextIntoTextfield(page, 3, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  TypeTextIntoTextField(page, 3, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
   SelectTextWithMouse(page, 128.0, 103.0, 63.0);
   CheckSelection(page, CFX_WideString(L"ABC"));
 
@@ -584,7 +584,7 @@
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
 
-  TypeTextIntoTextfield(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
 
   // Test selecting first character in forward direction.
   SelectTextWithKeyboard(page, 1, FWL_VKEY_Right, 102.0, 63.0);
@@ -622,7 +622,7 @@
   FPDF_PAGE page = LoadPage(0);
   ASSERT_TRUE(page);
 
-  TypeTextIntoTextfield(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
 
   // Test selecting first character in forward direction.
   SelectTextWithMouse(page, 102.0, 107.0, 63.0);
@@ -646,3 +646,199 @@
 
   UnloadPage(page);
 }
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteTextFieldEntireSelection) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select entire contents of text field.
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  SelectTextWithMouse(page, 191.0, 102.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+  CheckSelection(page, CFX_WideString());
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteTextFieldSelectionMiddle) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select middle section of text.
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  SelectTextWithMouse(page, 170.0, 125.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCJKL"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteTextFieldSelectionLeft) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select first few characters of text.
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  SelectTextWithMouse(page, 102.0, 132.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCD"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"EFGHIJKL"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteTextFieldSelectionRight) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select last few characters of text.
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  SelectTextWithMouse(page, 191.0, 165.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"IJKL"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGH"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEmptyTextFieldSelection) {
+  // Open file with form text field.
+  EXPECT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Do not select text.
+  TypeTextIntoTextField(page, 12, FPDF_FORMFIELD_TEXTFIELD, 120.0, 120.0);
+  CheckSelection(page, CFX_WideString());
+
+  // Test that attempt to delete empty text selection has no effect.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEditableComboBoxEntireSelection) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select entire contents of user-editable combobox text field.
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJ"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString());
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEditableComboBoxSelectionMiddle) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select middle section of text.
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  SelectTextWithMouse(page, 168.0, 127.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"DEFGH"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"ABCIJ"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEditableComboBoxSelectionLeft) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select first few characters of text.
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  SelectTextWithMouse(page, 102.0, 132.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"ABCD"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"EFGHIJ"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEditableComboBoxSelectionRight) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Select last few characters of text.
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  SelectTextWithMouse(page, 178.0, 152.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"GHIJ"));
+
+  // Test deleting current text selection. Select what remains after deletion to
+  // check that remaining text is as expected.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEF"));
+
+  UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, DeleteEmptyEditableComboBoxSelection) {
+  // Open file with form comboboxes.
+  EXPECT_TRUE(OpenDocument("combobox_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Do not select text.
+  TypeTextIntoTextField(page, 10, FPDF_FORMFIELD_COMBOBOX, 102.0, 62.0);
+  CheckSelection(page, CFX_WideString());
+
+  // Test that attempt to delete empty text selection has no effect.
+  FORM_DeleteSelectedText(form_handle(), page);
+  SelectTextWithMouse(page, 178.0, 102.0, 63.0);
+  CheckSelection(page, CFX_WideString(L"ABCDEFGHIJ"));
+
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 546ae47..97bacbb 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -179,6 +179,7 @@
     CHK(FORM_OnKeyUp);
     CHK(FORM_OnChar);
     CHK(FORM_GetSelectedText);
+    CHK(FORM_DeleteSelectedText);
     CHK(FORM_ForceToKillFocus);
     CHK(FPDFPage_HasFormFieldAtPoint);
     CHK(FPDFPage_FormFieldZOrderAtPoint);
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 08008eb..5340978 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -37,6 +37,7 @@
   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 bool HitTest(CPDFSDK_PageView* pPageView,
                        CPDFSDK_Annot* pAnnot,
                        const CFX_PointF& point) = 0;
diff --git a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp
index 8de2f1e..90c8cc6 100644
--- a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp
@@ -184,6 +184,11 @@
   return CFX_WideString();
 }
 
+void CPWL_ComboBox::DeleteSelectedText() {
+  if (m_pEdit)
+    m_pEdit->DeleteSelectedText();
+}
+
 CFX_WideString CPWL_ComboBox::GetText() const {
   if (m_pEdit) {
     return m_pEdit->GetText();
diff --git a/fpdfsdk/pdfwindow/cpwl_combo_box.h b/fpdfsdk/pdfwindow/cpwl_combo_box.h
index 12c0fe9..530ff0a 100644
--- a/fpdfsdk/pdfwindow/cpwl_combo_box.h
+++ b/fpdfsdk/pdfwindow/cpwl_combo_box.h
@@ -63,6 +63,7 @@
   void SetFocus() override;
   void KillFocus() override;
   CFX_WideString GetSelectedText() override;
+  void DeleteSelectedText() override;
 
   void SetFillerNotify(IPWL_Filler_Notify* pNotify);
 
diff --git a/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp b/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp
index 9ca994f..3224284 100644
--- a/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp
@@ -194,3 +194,75 @@
   GetCPWLComboBox()->SetEditSelection(49, 50);
   EXPECT_STREQ(L"r", GetCPWLComboBox()->GetSelectedText().c_str());
 }
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteEntireTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), i + 'A', 0));
+  }
+
+  GetCPWLComboBox()->SetEditSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->DeleteSelectedText();
+  EXPECT_TRUE(GetCPWLComboBox()->GetText().IsEmpty());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionMiddle) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), i + 'A', 0));
+  }
+
+  GetCPWLComboBox()->SetEditSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionLeft) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), i + 'A', 0));
+  }
+
+  GetCPWLComboBox()->SetEditSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->DeleteSelectedText();
+  EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteTextSelectionRight) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), i + 'A', 0));
+  }
+
+  GetCPWLComboBox()->SetEditSelection(45, 50);
+  EXPECT_STREQ(L"nopqr", GetCPWLComboBox()->GetSelectedText().c_str());
+
+  GetCPWLComboBox()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
+               GetCPWLComboBox()->GetText().c_str());
+}
+
+TEST_F(CPWLComboBoxEditEmbeddertest, DeleteEmptyTextSelection) {
+  FormFillerAndWindowSetup(GetCPDFSDKAnnotUserEditable());
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(
+        GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnotUserEditable(), i + 'A', 0));
+  }
+
+  GetCPWLComboBox()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLComboBox()->GetText().c_str());
+}
diff --git a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
index c7e1f14..a3aac19 100644
--- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
@@ -59,6 +59,11 @@
   return CFX_WideString();
 }
 
+void CPWL_EditCtrl::DeleteSelectedText() {
+  if (m_pEdit)
+    m_pEdit->ClearSelection();
+}
+
 void CPWL_EditCtrl::RePosChildWnd() {
   m_pEdit->SetPlateRect(GetClientRect());
 }
diff --git a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h
index ef6989e..30c2d63 100644
--- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h
+++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h
@@ -61,6 +61,7 @@
   float GetFontSize() const override;
   void SetCursor() override;
   CFX_WideString GetSelectedText() override;
+  void DeleteSelectedText() override;
 
   void SetCaret(bool bVisible,
                 const CFX_PointF& ptHead,
diff --git a/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp b/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
index 9b15ad8..2b1bbd4 100644
--- a/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
@@ -123,3 +123,65 @@
   GetCPWLEdit()->SetSelection(49, 50);
   EXPECT_STREQ(L"r", GetCPWLEdit()->GetSelectedText().c_str());
 }
+
+TEST_F(CPWLEditEmbeddertest, DeleteEntireTextSelection) {
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+  }
+
+  GetCPWLEdit()->SetSelection(0, -1);
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->DeleteSelectedText();
+  EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionMiddle) {
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+  }
+
+  GetCPWLEdit()->SetSelection(12, 23);
+  EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionLeft) {
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+  }
+
+  GetCPWLEdit()->SetSelection(0, 5);
+  EXPECT_STREQ(L"ABCDE", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->DeleteSelectedText();
+  EXPECT_STREQ(L"FGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteTextSelectionRight) {
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+  }
+
+  GetCPWLEdit()->SetSelection(45, 50);
+  EXPECT_STREQ(L"nopqr", GetCPWLEdit()->GetSelectedText().c_str());
+
+  GetCPWLEdit()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm",
+               GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, DeleteEmptyTextSelection) {
+  for (int i = 0; i < 50; ++i) {
+    EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+  }
+
+  GetCPWLEdit()->DeleteSelectedText();
+  EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+               GetCPWLEdit()->GetText().c_str());
+}
diff --git a/fpdfsdk/pdfwindow/cpwl_wnd.cpp b/fpdfsdk/pdfwindow/cpwl_wnd.cpp
index 663a763..58824af 100644
--- a/fpdfsdk/pdfwindow/cpwl_wnd.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_wnd.cpp
@@ -369,6 +369,8 @@
   return CFX_WideString();
 }
 
+void CPWL_Wnd::DeleteSelectedText() {}
+
 bool CPWL_Wnd::OnMouseWheel(short zDelta,
                             const CFX_PointF& point,
                             uint32_t nFlag) {
diff --git a/fpdfsdk/pdfwindow/cpwl_wnd.h b/fpdfsdk/pdfwindow/cpwl_wnd.h
index b22c5db..d56369c 100644
--- a/fpdfsdk/pdfwindow/cpwl_wnd.h
+++ b/fpdfsdk/pdfwindow/cpwl_wnd.h
@@ -202,6 +202,7 @@
   virtual float GetFontSize() const;
 
   virtual CFX_WideString GetSelectedText();
+  virtual void DeleteSelectedText();
   virtual CFX_FloatRect GetFocusRect() const;
   virtual CFX_FloatRect GetClientRect() const;