From 1c7f1420b78f37ec1619ab1552261e9ce3947a3b Mon Sep 17 00:00:00 2001 From: Diana Gage Date: Mon, 24 Jul 2017 11:19:52 -0700 Subject: 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 Commit-Queue: Diana Gage --- fpdfsdk/cpdfsdk_annothandlermgr.cpp | 4 + fpdfsdk/cpdfsdk_annothandlermgr.h | 1 + fpdfsdk/cpdfsdk_baannothandler.cpp | 2 + fpdfsdk/cpdfsdk_baannothandler.h | 1 + fpdfsdk/cpdfsdk_pageview.cpp | 8 + fpdfsdk/cpdfsdk_pageview.h | 1 + fpdfsdk/cpdfsdk_widgethandler.cpp | 5 + fpdfsdk/cpdfsdk_widgethandler.h | 1 + fpdfsdk/cpdfsdk_xfawidgethandler.cpp | 6 + fpdfsdk/cpdfsdk_xfawidgethandler.h | 1 + fpdfsdk/formfiller/cffl_formfiller.cpp | 14 ++ fpdfsdk/formfiller/cffl_formfiller.h | 1 + fpdfsdk/formfiller/cffl_interactiveformfiller.cpp | 9 + fpdfsdk/formfiller/cffl_interactiveformfiller.h | 1 + fpdfsdk/fpdfformfill.cpp | 8 + fpdfsdk/fpdfformfill_embeddertest.cpp | 224 ++++++++++++++++++++-- fpdfsdk/fpdfview_c_api_test.c | 1 + fpdfsdk/ipdfsdk_annothandler.h | 1 + fpdfsdk/pdfwindow/cpwl_combo_box.cpp | 5 + fpdfsdk/pdfwindow/cpwl_combo_box.h | 1 + fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp | 72 +++++++ fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp | 5 + fpdfsdk/pdfwindow/cpwl_edit_ctrl.h | 1 + fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp | 62 ++++++ fpdfsdk/pdfwindow/cpwl_wnd.cpp | 2 + fpdfsdk/pdfwindow/cpwl_wnd.h | 1 + public/fpdf_formfill.h | 16 ++ 27 files changed, 440 insertions(+), 14 deletions(-) diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp index 9e649f6dc6..fd77a73460 100644 --- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp +++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp @@ -81,6 +81,10 @@ CFX_WideString CPDFSDK_AnnotHandlerMgr::Annot_GetSelectedText( 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 ff2556f9dc..93c552bbfb 100644 --- a/fpdfsdk/cpdfsdk_annothandlermgr.h +++ b/fpdfsdk/cpdfsdk_annothandlermgr.h @@ -44,6 +44,7 @@ class CPDFSDK_AnnotHandlerMgr { 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 4984ee93cc..cf09d2bbcb 100644 --- a/fpdfsdk/cpdfsdk_baannothandler.cpp +++ b/fpdfsdk/cpdfsdk_baannothandler.cpp @@ -197,6 +197,8 @@ CFX_WideString CPDFSDK_BAAnnotHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) { 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 2af2f3ee99..7db9a4d7d7 100644 --- a/fpdfsdk/cpdfsdk_baannothandler.h +++ b/fpdfsdk/cpdfsdk_baannothandler.h @@ -38,6 +38,7 @@ class CPDFSDK_BAAnnotHandler : public IPDFSDK_AnnotHandler { 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 06761a5806..84a60fa42f 100644 --- a/fpdfsdk/cpdfsdk_pageview.cpp +++ b/fpdfsdk/cpdfsdk_pageview.cpp @@ -253,6 +253,14 @@ CFX_WideString CPDFSDK_PageView::GetSelectedText() { 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 9eebb6e424..d4b7721575 100644 --- a/fpdfsdk/cpdfsdk_pageview.h +++ b/fpdfsdk/cpdfsdk_pageview.h @@ -61,6 +61,7 @@ class CPDFSDK_PageView final : public CPDF_Page::View { } 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 d916567bdd..1c802a3ba7 100644 --- a/fpdfsdk/cpdfsdk_widgethandler.cpp +++ b/fpdfsdk/cpdfsdk_widgethandler.cpp @@ -287,6 +287,11 @@ CFX_WideString CPDFSDK_WidgetHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) { 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 aac3619a44..2d33ff5686 100644 --- a/fpdfsdk/cpdfsdk_widgethandler.h +++ b/fpdfsdk/cpdfsdk_widgethandler.h @@ -39,6 +39,7 @@ class CPDFSDK_WidgetHandler : public IPDFSDK_AnnotHandler { 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 aa4c0f170a..746d1ca763 100644 --- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp +++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp @@ -97,11 +97,17 @@ CFX_FloatRect CPDFSDK_XFAWidgetHandler::GetViewBBox(CPDFSDK_PageView* pPageView, 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 65e5e452d2..3d06948116 100644 --- a/fpdfsdk/cpdfsdk_xfawidgethandler.h +++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h @@ -34,6 +34,7 @@ class CPDFSDK_XFAWidgetHandler : public IPDFSDK_AnnotHandler { 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 edbd671f29..a37a7501d0 100644 --- a/fpdfsdk/formfiller/cffl_formfiller.cpp +++ b/fpdfsdk/formfiller/cffl_formfiller.cpp @@ -245,6 +245,20 @@ CFX_WideString CFFL_FormFiller::GetSelectedText(CPDFSDK_Annot* pAnnot) { 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 3eedebea47..96b7a69b29 100644 --- a/fpdfsdk/formfiller/cffl_formfiller.h +++ b/fpdfsdk/formfiller/cffl_formfiller.h @@ -75,6 +75,7 @@ class CFFL_FormFiller : public IPWL_Provider, public CPWL_TimerHandler { 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 8a81f4c40d..24bfd3c3b2 100644 --- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp +++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp @@ -523,6 +523,15 @@ CFX_WideString CFFL_InteractiveFormFiller::GetSelectedText( 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 fb141e17a4..744d522fbc 100644 --- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h +++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h @@ -84,6 +84,7 @@ class CFFL_InteractiveFormFiller : public IPWL_Filler_Notify { 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 24cd64efa1..627bd0a925 100644 --- a/fpdfsdk/fpdfformfill.cpp +++ b/fpdfsdk/fpdfformfill.cpp @@ -383,6 +383,14 @@ DLLEXPORT unsigned long STDCALL FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, 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 70899276b3..d0fd6de94d 100644 --- a/fpdfsdk/fpdfformfill_embeddertest.cpp +++ b/fpdfsdk/fpdfformfill_embeddertest.cpp @@ -22,7 +22,7 @@ using testing::Return; 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 @@ TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextEmptyAndBasicKeyboard) { 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 @@ TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextEmptyAndBasicMouse) { 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 @@ TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextFragmentsKeyBoard) { 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 @@ TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextFragmentsMouse) { 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 @@ TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextEmptyAndBasicNormalComboBox) { 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 @@ TEST_F(FPDFFormFillEmbeddertest, 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 @@ TEST_F(FPDFFormFillEmbeddertest, 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 @@ TEST_F(FPDFFormFillEmbeddertest, 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 @@ TEST_F(FPDFFormFillEmbeddertest, 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 @@ TEST_F(FPDFFormFillEmbeddertest, 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 546ae47512..97bacbba54 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -179,6 +179,7 @@ int CheckPDFiumCApi() { 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 08008eb996..5340978308 100644 --- a/fpdfsdk/ipdfsdk_annothandler.h +++ b/fpdfsdk/ipdfsdk_annothandler.h @@ -37,6 +37,7 @@ class IPDFSDK_AnnotHandler { 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 8de2f1e733..90c8cc6dc0 100644 --- a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp +++ b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp @@ -184,6 +184,11 @@ CFX_WideString CPWL_ComboBox::GetSelectedText() { 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 12c0fe9878..530ff0a07e 100644 --- a/fpdfsdk/pdfwindow/cpwl_combo_box.h +++ b/fpdfsdk/pdfwindow/cpwl_combo_box.h @@ -63,6 +63,7 @@ class CPWL_ComboBox : public CPWL_Wnd { 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 9ca994f2e1..3224284ee2 100644 --- a/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp +++ b/fpdfsdk/pdfwindow/cpwl_combo_box_embeddertest.cpp @@ -194,3 +194,75 @@ TEST_F(CPWLComboBoxEditEmbeddertest, GetSelectedTextFragmentsEditable) { 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 c7e1f14499..a3aac19e20 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp +++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp @@ -59,6 +59,11 @@ CFX_WideString CPWL_EditCtrl::GetSelectedText() { 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 ef6989e637..30c2d63419 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h +++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h @@ -61,6 +61,7 @@ class CPWL_EditCtrl : public CPWL_Wnd { 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 9b15ad887d..2b1bbd4445 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp +++ b/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp @@ -123,3 +123,65 @@ TEST_F(CPWLEditEmbeddertest, GetSelectedTextFragments) { 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 663a763e3c..58824afdbd 100644 --- a/fpdfsdk/pdfwindow/cpwl_wnd.cpp +++ b/fpdfsdk/pdfwindow/cpwl_wnd.cpp @@ -369,6 +369,8 @@ CFX_WideString CPWL_Wnd::GetSelectedText() { 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 b22c5dba21..d56369cb52 100644 --- a/fpdfsdk/pdfwindow/cpwl_wnd.h +++ b/fpdfsdk/pdfwindow/cpwl_wnd.h @@ -202,6 +202,7 @@ class CPWL_Wnd : public CPWL_TimerHandler, public CFX_Observable { virtual float GetFontSize() const; virtual CFX_WideString GetSelectedText(); + virtual void DeleteSelectedText(); virtual CFX_FloatRect GetFocusRect() const; virtual CFX_FloatRect GetClientRect() const; diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h index 5a15cd9a02..83a4e58bdc 100644 --- a/public/fpdf_formfill.h +++ b/public/fpdf_formfill.h @@ -1377,6 +1377,22 @@ DLLEXPORT unsigned long STDCALL FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, void* buffer, 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. + * Parameters: + * hHandle - Handle to the form fill module. Returned by + * FPDFDOC_InitFormFillEnvironment. + * page - Handle to the page. Returned by FPDF_LoadPage + * function. + * Return Value: + * None. + **/ +DLLEXPORT void STDCALL FORM_DeleteSelectedText(FPDF_FORMHANDLE hHandle, + FPDF_PAGE page); + /** * Function: FORM_ForceToKillFocus. * You can call this member function to force to kill the focus of the -- cgit v1.2.3