Add experimental FORM_SelectAllText() API.

This API allows programmers to easily select all the text in the focused
form field. Add a FPDFFormFillEmbedderTest test case for it, and also
use it in place of several FPDFFormFillEmbedderTest helper methods that
selects all text with the mouse.

Bug: pdfium:1543
Change-Id: I0cc313dfd3cb2e510669f03771e18b45f14c4577
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70739
Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index 0ee98d4..790ba15 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -93,6 +93,10 @@
   GetAnnotHandler(pAnnot)->ReplaceSelection(pAnnot, text);
 }
 
+bool CPDFSDK_AnnotHandlerMgr::Annot_SelectAllText(CPDFSDK_Annot* pAnnot) {
+  return GetAnnotHandler(pAnnot)->SelectAllText(pAnnot);
+}
+
 bool CPDFSDK_AnnotHandlerMgr::Annot_CanUndo(CPDFSDK_Annot* pAnnot) {
   return GetAnnotHandler(pAnnot)->CanUndo(pAnnot);
 }
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.h b/fpdfsdk/cpdfsdk_annothandlermgr.h
index dd01348..c7dea78 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -49,6 +49,7 @@
   WideString Annot_GetText(CPDFSDK_Annot* pAnnot);
   WideString Annot_GetSelectedText(CPDFSDK_Annot* pAnnot);
   void Annot_ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text);
+  bool Annot_SelectAllText(CPDFSDK_Annot* pAnnot);
 
   bool Annot_CanUndo(CPDFSDK_Annot* pAnnot);
   bool Annot_CanRedo(CPDFSDK_Annot* pAnnot);
diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp
index 5566e99..91c3e7d 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -274,6 +274,10 @@
 void CPDFSDK_BAAnnotHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot,
                                               const WideString& text) {}
 
+bool CPDFSDK_BAAnnotHandler::SelectAllText(CPDFSDK_Annot* pAnnot) {
+  return false;
+}
+
 bool CPDFSDK_BAAnnotHandler::CanUndo(CPDFSDK_Annot* pAnnot) {
   return false;
 }
diff --git a/fpdfsdk/cpdfsdk_baannothandler.h b/fpdfsdk/cpdfsdk_baannothandler.h
index 3eaf446..90e0f73 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -37,6 +37,7 @@
   WideString GetText(CPDFSDK_Annot* pAnnot) override;
   WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
   void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
+  bool SelectAllText(CPDFSDK_Annot* pAnnot) override;
   bool CanUndo(CPDFSDK_Annot* pAnnot) override;
   bool CanRedo(CPDFSDK_Annot* pAnnot) override;
   bool Undo(CPDFSDK_Annot* pAnnot) override;
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp
index 2337f30..52215ef 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -228,6 +228,15 @@
   }
 }
 
+bool CPDFSDK_PageView::SelectAllText() {
+  CPDFSDK_Annot* annot = GetFocusAnnot();
+  if (!annot)
+    return false;
+
+  CPDFSDK_AnnotHandlerMgr* handler = m_pFormFillEnv->GetAnnotHandlerMgr();
+  return handler->Annot_SelectAllText(annot);
+}
+
 bool CPDFSDK_PageView::CanUndo() {
   if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
     CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
diff --git a/fpdfsdk/cpdfsdk_pageview.h b/fpdfsdk/cpdfsdk_pageview.h
index 1c947b9..50680f3 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -57,6 +57,7 @@
   WideString GetFocusedFormText();
   WideString GetSelectedText();
   void ReplaceSelection(const WideString& text);
+  bool SelectAllText();
 
   bool CanUndo();
   bool CanRedo();
diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp
index c6f9e32..63d0edf 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -276,6 +276,10 @@
     m_pFormFiller->ReplaceSelection(pAnnot, text);
 }
 
+bool CPDFSDK_WidgetHandler::SelectAllText(CPDFSDK_Annot* pAnnot) {
+  return !pAnnot->IsSignatureWidget() && m_pFormFiller->SelectAllText(pAnnot);
+}
+
 bool CPDFSDK_WidgetHandler::CanUndo(CPDFSDK_Annot* pAnnot) {
   return !pAnnot->IsSignatureWidget() && m_pFormFiller->CanUndo(pAnnot);
 }
diff --git a/fpdfsdk/cpdfsdk_widgethandler.h b/fpdfsdk/cpdfsdk_widgethandler.h
index afbbc0d..5e2236e 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -37,6 +37,7 @@
   WideString GetText(CPDFSDK_Annot* pAnnot) override;
   WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
   void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
+  bool SelectAllText(CPDFSDK_Annot* pAnnot) override;
   bool CanUndo(CPDFSDK_Annot* pAnnot) override;
   bool CanRedo(CPDFSDK_Annot* pAnnot) override;
   bool Undo(CPDFSDK_Annot* pAnnot) override;
diff --git a/fpdfsdk/formfiller/cffl_formfiller.cpp b/fpdfsdk/formfiller/cffl_formfiller.cpp
index 3f095bb..7856254 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -213,6 +213,14 @@
   pWnd->ReplaceSelection(text);
 }
 
+bool CFFL_FormFiller::SelectAllText() {
+  if (!IsValid())
+    return false;
+
+  CPWL_Wnd* pWnd = GetPWLWindow(GetCurPageView(), false);
+  return pWnd && pWnd->SelectAllText();
+}
+
 bool CFFL_FormFiller::CanUndo() {
   if (!IsValid())
     return false;
diff --git a/fpdfsdk/formfiller/cffl_formfiller.h b/fpdfsdk/formfiller/cffl_formfiller.h
index ba0f753..31860f7 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -76,6 +76,7 @@
   WideString GetText();
   WideString GetSelectedText();
   void ReplaceSelection(const WideString& text);
+  bool SelectAllText();
 
   bool CanUndo();
   bool CanRedo();
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index b8be70e..841c1af 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -530,6 +530,12 @@
   pFormFiller->ReplaceSelection(text);
 }
 
+bool CFFL_InteractiveFormFiller::SelectAllText(CPDFSDK_Annot* pAnnot) {
+  ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
+  CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot);
+  return pAnnot && pFormFiller->SelectAllText();
+}
+
 bool CFFL_InteractiveFormFiller::CanUndo(CPDFSDK_Annot* pAnnot) {
   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot);
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.h b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
index d614b24..d663100 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -89,6 +89,7 @@
   WideString GetText(CPDFSDK_Annot* pAnnot);
   WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
   void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text);
+  bool SelectAllText(CPDFSDK_Annot* pAnnot);
 
   bool CanUndo(CPDFSDK_Annot* pAnnot);
   bool CanRedo(CPDFSDK_Annot* pAnnot);
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index a1a74b9..bbfc64b 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -544,6 +544,12 @@
   pPageView->ReplaceSelection(WideStringFromFPDFWideString(wsText));
 }
 
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle,
+                                                       FPDF_PAGE page) {
+  CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+  return pPageView && pPageView->SelectAllText();
+}
+
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle,
                                                  FPDF_PAGE page) {
   CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
diff --git a/fpdfsdk/fpdf_formfill_embeddertest.cpp b/fpdfsdk/fpdf_formfill_embeddertest.cpp
index eaadb27..3eaadee 100644
--- a/fpdfsdk/fpdf_formfill_embeddertest.cpp
+++ b/fpdfsdk/fpdf_formfill_embeddertest.cpp
@@ -134,6 +134,11 @@
     FORM_OnLButtonUp(form_handle(), page_, 0, end.x, end.y);
   }
 
+  void SelectAllTextAtPoint(const CFX_PointF& point) {
+    FocusOnPoint(point);
+    EXPECT_TRUE(FORM_SelectAllText(form_handle(), page_));
+  }
+
   void CheckSelection(WideStringView expected_string) {
     unsigned long actual_len =
         FORM_GetSelectedText(form_handle(), page_, nullptr, 0);
@@ -148,6 +153,10 @@
     EXPECT_EQ(expected_string, WideString::FromUTF16LE(buf.data(), num_chars));
   }
 
+  void FocusOnPoint(const CFX_PointF& point) {
+    EXPECT_TRUE(FORM_OnFocus(form_handle(), page(), 0, point.x, point.y));
+  }
+
   void CheckFocusedFieldText(WideStringView expected_string) {
     unsigned long actual_len =
         FORM_GetFocusedText(form_handle(), page_, nullptr, 0);
@@ -214,11 +223,11 @@
   }
 
   void SelectAllCharLimitFormTextWithMouse() {
-    SelectTextWithMouse(CharLimitFormEnd(), CharLimitFormBegin());
+    SelectAllTextAtPoint(CharLimitFormBegin());
   }
 
   void SelectAllRegularFormTextWithMouse() {
-    SelectTextWithMouse(RegularFormEnd(), RegularFormBegin());
+    SelectAllTextAtPoint(RegularFormBegin());
   }
 
   const CFX_PointF& CharLimitFormBegin() const {
@@ -298,17 +307,13 @@
   }
 
   void SelectAllEditableFormTextWithMouse() {
-    SelectTextWithMouse(EditableFormEnd(), EditableFormBegin());
+    SelectAllTextAtPoint(EditableFormBegin());
   }
 
   void FocusOnEditableForm() { FocusOnPoint(EditableFormDropDown()); }
 
   void FocusOnNonEditableForm() { FocusOnPoint(NonEditableFormDropDown()); }
 
-  void FocusOnPoint(const CFX_PointF& point) {
-    EXPECT_EQ(true, FORM_OnFocus(form_handle(), page(), 0, point.x, point.y));
-  }
-
   const CFX_PointF& EditableFormBegin() const {
     static const CFX_PointF point = EditableFormAtX(kFormBeginX);
     return point;
@@ -1532,6 +1537,44 @@
   UnloadPage(page);
 }
 
+TEST_F(FPDFFormFillEmbedderTest, SelectAllText) {
+  ASSERT_TRUE(OpenDocument("text_form.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+
+  // Test bad arguments.
+  EXPECT_FALSE(FORM_SelectAllText(nullptr, nullptr));
+  EXPECT_FALSE(FORM_SelectAllText(form_handle(), nullptr));
+  EXPECT_FALSE(FORM_SelectAllText(nullptr, page));
+
+  // Focus on the text field and add some text.
+  EXPECT_TRUE(FORM_OnFocus(form_handle(), page, 0, 115, 115));
+  ScopedFPDFWideString text_to_insert = GetFPDFWideString(L"Hello");
+  FORM_ReplaceSelection(form_handle(), page, text_to_insert.get());
+
+  // Sanity check text field data.
+  uint16_t buffer[6];
+  ASSERT_EQ(12u, FORM_GetFocusedText(form_handle(), page, nullptr, 0));
+  ASSERT_EQ(12u,
+            FORM_GetFocusedText(form_handle(), page, buffer, sizeof(buffer)));
+  EXPECT_EQ("Hello", GetPlatformString(buffer));
+
+  // Check there is no selection.
+  ASSERT_EQ(2u, FORM_GetSelectedText(form_handle(), page, nullptr, 0));
+  ASSERT_EQ(2u,
+            FORM_GetSelectedText(form_handle(), page, buffer, sizeof(buffer)));
+  EXPECT_EQ("", GetPlatformString(buffer));
+
+  // Check FORM_SelectAllText() works.
+  EXPECT_TRUE(FORM_SelectAllText(form_handle(), page));
+  ASSERT_EQ(12u, FORM_GetSelectedText(form_handle(), page, nullptr, 0));
+  ASSERT_EQ(12u,
+            FORM_GetSelectedText(form_handle(), page, buffer, sizeof(buffer)));
+  EXPECT_EQ("Hello", GetPlatformString(buffer));
+
+  UnloadPage(page);
+}
+
 TEST_F(FPDFFormFillTextFormEmbedderTest, GetSelectedTextEmptyAndBasicKeyboard) {
   // Test empty selection.
   CheckFocusedFieldText(L"");
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index c368da3..f76d3d2 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -270,6 +270,7 @@
     CHK(FORM_OnRButtonUp);
     CHK(FORM_Redo);
     CHK(FORM_ReplaceSelection);
+    CHK(FORM_SelectAllText);
     CHK(FORM_SetFocusedAnnot);
     CHK(FORM_SetIndexSelected);
     CHK(FORM_Undo);
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.cpp
index 8cc6198..c5e956f 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.cpp
@@ -296,6 +296,15 @@
   return pWidgetHandler->PasteText(pXFAWidget->GetXFAFFWidget(), text);
 }
 
+bool CPDFXFA_WidgetHandler::SelectAllText(CPDFSDK_Annot* pAnnot) {
+  CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pAnnot);
+  if (!pXFAWidget)
+    return false;
+
+  CXFA_FFWidgetHandler* pWidgetHandler = GetXFAFFWidgetHandler(pXFAWidget);
+  return pWidgetHandler->SelectAllText(pXFAWidget->GetXFAFFWidget());
+}
+
 bool CPDFXFA_WidgetHandler::CanUndo(CPDFSDK_Annot* pAnnot) {
   CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pAnnot);
   if (!pXFAWidget)
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.h b/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.h
index abef600..abad547 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.h
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_widgethandler.h
@@ -39,6 +39,7 @@
   WideString GetText(CPDFSDK_Annot* pAnnot) override;
   WideString GetSelectedText(CPDFSDK_Annot* pAnnot) override;
   void ReplaceSelection(CPDFSDK_Annot* pAnnot, const WideString& text) override;
+  bool SelectAllText(CPDFSDK_Annot* pAnnot) override;
   bool CanUndo(CPDFSDK_Annot* pAnnot) override;
   bool CanRedo(CPDFSDK_Annot* pAnnot) override;
   bool Undo(CPDFSDK_Annot* pAnnot) override;
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 234d0b5..6150bdc 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -35,6 +35,7 @@
   virtual WideString GetSelectedText(CPDFSDK_Annot* pAnnot) = 0;
   virtual void ReplaceSelection(CPDFSDK_Annot* pAnnot,
                                 const WideString& text) = 0;
+  virtual bool SelectAllText(CPDFSDK_Annot* pAnnot) = 0;
   virtual bool CanUndo(CPDFSDK_Annot* pAnnot) = 0;
   virtual bool CanRedo(CPDFSDK_Annot* pAnnot) = 0;
   virtual bool Undo(CPDFSDK_Annot* pAnnot) = 0;
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
index e364650..7fe2517 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
@@ -205,6 +205,10 @@
     m_pEdit->ReplaceSelection(text);
 }
 
+bool CPWL_ComboBox::SelectAllText() {
+  return m_pEdit && m_pEdit->SelectAllText();
+}
+
 bool CPWL_ComboBox::CanUndo() {
   return m_pEdit && m_pEdit->CanUndo();
 }
@@ -419,7 +423,7 @@
 
 void CPWL_ComboBox::SelectAll() {
   if (m_pEdit && HasFlag(PCBS_ALLOWCUSTOMTEXT))
-    m_pEdit->SelectAll();
+    m_pEdit->SelectAllText();
 }
 
 CFX_FloatRect CPWL_ComboBox::GetFocusRect() const {
@@ -583,7 +587,7 @@
     return;
 
   SetSelectText();
-  SelectAll();
+  SelectAllText();
   m_pEdit->SetFocus();
   SetPopup(false);
   // Note, |this| may no longer be viable at this point. If more work needs to
@@ -595,9 +599,9 @@
 }
 
 void CPWL_ComboBox::SetSelectText() {
-  m_pEdit->SelectAll();
+  m_pEdit->SelectAllText();
   m_pEdit->ReplaceSelection(m_pList->GetText());
-  m_pEdit->SelectAll();
+  m_pEdit->SelectAllText();
   m_nSelectItem = m_pList->GetCurSel();
 }
 
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
index 6f71c71..cf1a875 100644
--- a/fpdfsdk/pwl/cpwl_combo_box.h
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
@@ -68,6 +68,7 @@
   WideString GetText() override;
   WideString GetSelectedText() override;
   void ReplaceSelection(const WideString& text) override;
+  bool SelectAllText() override;
   bool CanUndo() override;
   bool CanRedo() override;
   bool Undo() override;
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.cpp b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
index e4482a1..3e16b62 100644
--- a/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.cpp
@@ -51,6 +51,11 @@
   m_pEdit->ReplaceSelection(text);
 }
 
+bool CPWL_EditCtrl::SelectAllText() {
+  m_pEdit->SelectAll();
+  return true;
+}
+
 bool CPWL_EditCtrl::RePosChildWnd() {
   m_pEdit->SetPlateRect(GetClientRect());
   return true;
@@ -206,7 +211,7 @@
         CutText();
         return true;
       case 'A' - 'A' + 1:
-        SelectAll();
+        SelectAllText();
         return true;
       case 'Z' - 'A' + 1:
         if (bShift)
@@ -348,10 +353,6 @@
     m_pEdit->ClearSelection();
 }
 
-void CPWL_EditCtrl::SelectAll() {
-  m_pEdit->SelectAll();
-}
-
 void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
   m_pEdit->SetScrollPos(point);
 }
diff --git a/fpdfsdk/pwl/cpwl_edit_ctrl.h b/fpdfsdk/pwl/cpwl_edit_ctrl.h
index 67bd247..f5ccf3c 100644
--- a/fpdfsdk/pwl/cpwl_edit_ctrl.h
+++ b/fpdfsdk/pwl/cpwl_edit_ctrl.h
@@ -32,7 +32,6 @@
   void SetSelection(int32_t nStartChar, int32_t nEndChar);
   std::pair<int32_t, int32_t> GetSelection() const;
   void ClearSelection();
-  void SelectAll();
 
   CFX_PointF GetScrollPos() const;
   void SetScrollPos(const CFX_PointF& point);
@@ -40,11 +39,6 @@
   void SetCharSet(uint8_t nCharSet) { m_nCharSet = nCharSet; }
   int32_t GetCharSet() const;
 
-  bool CanUndo() override;
-  bool CanRedo() override;
-  bool Undo() override;
-  bool Redo() override;
-
   void SetReadyToInput();
 
   // CPWL_Wnd:
@@ -65,6 +59,11 @@
   WideString GetText() override;
   WideString GetSelectedText() override;
   void ReplaceSelection(const WideString& text) override;
+  bool SelectAllText() override;
+  bool CanUndo() override;
+  bool CanRedo() override;
+  bool Undo() override;
+  bool Redo() override;
 
   bool SetCaret(bool bVisible,
                 const CFX_PointF& ptHead,
diff --git a/fpdfsdk/pwl/cpwl_wnd.cpp b/fpdfsdk/pwl/cpwl_wnd.cpp
index a2379f9..1d031f0 100644
--- a/fpdfsdk/pwl/cpwl_wnd.cpp
+++ b/fpdfsdk/pwl/cpwl_wnd.cpp
@@ -334,6 +334,10 @@
 
 void CPWL_Wnd::ReplaceSelection(const WideString& text) {}
 
+bool CPWL_Wnd::SelectAllText() {
+  return false;
+}
+
 bool CPWL_Wnd::CanUndo() {
   return false;
 }
diff --git a/fpdfsdk/pwl/cpwl_wnd.h b/fpdfsdk/pwl/cpwl_wnd.h
index 917e018..b3730a0 100644
--- a/fpdfsdk/pwl/cpwl_wnd.h
+++ b/fpdfsdk/pwl/cpwl_wnd.h
@@ -175,6 +175,7 @@
   virtual WideString GetText();
   virtual WideString GetSelectedText();
   virtual void ReplaceSelection(const WideString& text);
+  virtual bool SelectAllText();
 
   virtual bool CanUndo();
   virtual bool CanRedo();
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index c73cbf7..8f9c94d7 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -1569,6 +1569,21 @@
                                                      FPDF_WIDESTRING wsText);
 
 /*
+ * Experimental API
+ * Function: FORM_SelectAllText
+ *       Call this function to select all the text within the currently focused
+ *       form text field or form combobox text field.
+ * Parameters:
+ *       hHandle     -   Handle to the form fill module, as returned by
+ *                       FPDFDOC_InitFormFillEnvironment().
+ *       page        -   Handle to the page, as returned by FPDF_LoadPage().
+ * Return Value:
+ *       Whether the operation succeeded or not.
+ */
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page);
+
+/*
  * Function: FORM_CanUndo
  *       Find out if it is possible for the current focused widget in a given
  *       form to perform an undo operation.
diff --git a/xfa/fxfa/cxfa_ffwidgethandler.cpp b/xfa/fxfa/cxfa_ffwidgethandler.cpp
index 998f8d2..6c6d6ef 100644
--- a/xfa/fxfa/cxfa_ffwidgethandler.cpp
+++ b/xfa/fxfa/cxfa_ffwidgethandler.cpp
@@ -162,6 +162,14 @@
   widget->Paste(text);
 }
 
+bool CXFA_FFWidgetHandler::SelectAllText(CXFA_FFWidget* widget) {
+  if (!widget->CanSelectAll())
+    return false;
+
+  widget->SelectAll();
+  return true;
+}
+
 bool CXFA_FFWidgetHandler::CanUndo(CXFA_FFWidget* widget) {
   return widget->CanUndo();
 }
diff --git a/xfa/fxfa/cxfa_ffwidgethandler.h b/xfa/fxfa/cxfa_ffwidgethandler.h
index e5de8b8..778cc10 100644
--- a/xfa/fxfa/cxfa_ffwidgethandler.h
+++ b/xfa/fxfa/cxfa_ffwidgethandler.h
@@ -52,6 +52,7 @@
   WideString GetText(CXFA_FFWidget* widget);
   WideString GetSelectedText(CXFA_FFWidget* widget);
   void PasteText(CXFA_FFWidget* widget, const WideString& text);
+  bool SelectAllText(CXFA_FFWidget* widget);
 
   bool CanUndo(CXFA_FFWidget* widget);
   bool CanRedo(CXFA_FFWidget* widget);