summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Gage <drgage@google.com>2017-06-20 11:17:11 -0700
committerChromium commit bot <commit-bot@chromium.org>2017-06-20 21:41:22 +0000
commitdce2d72f9fbc166ee8eed0e362ab26e1e1a33cdd (patch)
tree410816fa09ffea9d2db198b5138f45ea55253824
parentb5c5ec06396158232d7f6955dde7b3512df0ae6e (diff)
downloadpdfium-dce2d72f9fbc166ee8eed0e362ab26e1e1a33cdd.tar.xz
Add FORM_GetSelectedText() function.
This function copies the selected text from a form text field or form combobox text field into the buffer parameter and returns the length of the selected text string. When buffer is a nullptr or buflen is less than the length of the selected text, this function does not modify the buffer and only returns the selected text length. BUG=chromium:59266 Change-Id: Ie77de38e45bbe6f9ea033826c961435304eedfc7 Reviewed-on: https://pdfium-review.googlesource.com/6413 Reviewed-by: dsinclair <dsinclair@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
-rw-r--r--fpdfsdk/cpdfsdk_annothandlermgr.cpp5
-rw-r--r--fpdfsdk/cpdfsdk_annothandlermgr.h2
-rw-r--r--fpdfsdk/cpdfsdk_baannothandler.cpp4
-rw-r--r--fpdfsdk/cpdfsdk_baannothandler.h1
-rw-r--r--fpdfsdk/cpdfsdk_pageview.cpp10
-rw-r--r--fpdfsdk/cpdfsdk_pageview.h2
-rw-r--r--fpdfsdk/cpdfsdk_widgethandler.cpp7
-rw-r--r--fpdfsdk/cpdfsdk_widgethandler.h1
-rw-r--r--fpdfsdk/cpdfsdk_xfawidgethandler.cpp5
-rw-r--r--fpdfsdk/cpdfsdk_xfawidgethandler.h1
-rw-r--r--fpdfsdk/formfiller/cffl_formfiller.cpp11
-rw-r--r--fpdfsdk/formfiller/cffl_formfiller.h2
-rw-r--r--fpdfsdk/formfiller/cffl_interactiveformfiller.cpp7
-rw-r--r--fpdfsdk/formfiller/cffl_interactiveformfiller.h2
-rw-r--r--fpdfsdk/fpdfformfill.cpp18
-rw-r--r--fpdfsdk/fpdfformfill_embeddertest.cpp173
-rw-r--r--fpdfsdk/fpdfview_c_api_test.c1
-rw-r--r--fpdfsdk/ipdfsdk_annothandler.h1
-rw-r--r--fpdfsdk/pdfwindow/cpwl_combo_box.cpp7
-rw-r--r--fpdfsdk/pdfwindow/cpwl_combo_box.h1
-rw-r--r--fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp7
-rw-r--r--fpdfsdk/pdfwindow/cpwl_edit_ctrl.h1
-rw-r--r--fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp138
-rw-r--r--fpdfsdk/pdfwindow/cpwl_wnd.cpp4
-rw-r--r--fpdfsdk/pdfwindow/cpwl_wnd.h1
-rw-r--r--public/fpdf_formfill.h23
26 files changed, 397 insertions, 38 deletions
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index 7ea301c0e4..2b089e5185 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -76,6 +76,11 @@ void CPDFSDK_AnnotHandlerMgr::Annot_OnLoad(CPDFSDK_Annot* pAnnot) {
GetAnnotHandler(pAnnot)->OnLoad(pAnnot);
}
+CFX_WideString CPDFSDK_AnnotHandlerMgr::Annot_GetSelectedText(
+ CPDFSDK_Annot* pAnnot) {
+ return GetAnnotHandler(pAnnot)->GetSelectedText(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 f36c3fb70e..5f6ff94b40 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.h
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.h
@@ -43,6 +43,8 @@ class CPDFSDK_AnnotHandlerMgr {
void Annot_OnCreate(CPDFSDK_Annot* pAnnot);
void Annot_OnLoad(CPDFSDK_Annot* pAnnot);
+ CFX_WideString Annot_GetSelectedText(CPDFSDK_Annot* pAnnot);
+
IPDFSDK_AnnotHandler* GetAnnotHandler(CPDFSDK_Annot* pAnnot) const;
void Annot_OnDraw(CPDFSDK_PageView* pPageView,
CPDFSDK_Annot* pAnnot,
diff --git a/fpdfsdk/cpdfsdk_baannothandler.cpp b/fpdfsdk/cpdfsdk_baannothandler.cpp
index fa83932a81..4984ee93cc 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.cpp
+++ b/fpdfsdk/cpdfsdk_baannothandler.cpp
@@ -193,6 +193,10 @@ CFX_FloatRect CPDFSDK_BAAnnotHandler::GetViewBBox(CPDFSDK_PageView* pPageView,
return pAnnot->GetRect();
}
+CFX_WideString CPDFSDK_BAAnnotHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+ return CFX_WideString();
+}
+
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 d5f170f452..2af2f3ee99 100644
--- a/fpdfsdk/cpdfsdk_baannothandler.h
+++ b/fpdfsdk/cpdfsdk_baannothandler.h
@@ -37,6 +37,7 @@ class CPDFSDK_BAAnnotHandler : public IPDFSDK_AnnotHandler {
void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
CPDFSDK_Annot* pAnnot) override;
+ CFX_WideString GetSelectedText(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 982eed1b21..aae245e298 100644
--- a/fpdfsdk/cpdfsdk_pageview.cpp
+++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -241,6 +241,16 @@ CPDFSDK_Annot* CPDFSDK_PageView::GetAnnotByXFAWidget(CXFA_FFWidget* hWidget) {
}
#endif // PDF_ENABLE_XFA
+CFX_WideString CPDFSDK_PageView::GetSelectedText() {
+ if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
+ CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
+ m_pFormFillEnv->GetAnnotHandlerMgr();
+ return pAnnotHandlerMgr->Annot_GetSelectedText(pAnnot);
+ }
+
+ return CFX_WideString();
+}
+
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 8bede08a5d..9eebb6e424 100644
--- a/fpdfsdk/cpdfsdk_pageview.h
+++ b/fpdfsdk/cpdfsdk_pageview.h
@@ -60,6 +60,8 @@ class CPDFSDK_PageView final : public CPDF_Page::View {
return m_pFormFillEnv.Get();
}
+ CFX_WideString GetSelectedText();
+
bool OnLButtonDown(const CFX_PointF& point, uint32_t nFlag);
bool OnLButtonUp(const CFX_PointF& point, uint32_t nFlag);
#ifdef PDF_ENABLE_XFA
diff --git a/fpdfsdk/cpdfsdk_widgethandler.cpp b/fpdfsdk/cpdfsdk_widgethandler.cpp
index c34f766793..68d95edb0e 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_widgethandler.cpp
@@ -280,6 +280,13 @@ CFX_FloatRect CPDFSDK_WidgetHandler::GetViewBBox(CPDFSDK_PageView* pPageView,
return CFX_FloatRect(0, 0, 0, 0);
}
+CFX_WideString CPDFSDK_WidgetHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+ if (!pAnnot->IsSignatureWidget() && m_pFormFiller)
+ return m_pFormFiller->GetSelectedText(pAnnot);
+
+ return CFX_WideString();
+}
+
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 4e8c9ef480..9ef190f54d 100644
--- a/fpdfsdk/cpdfsdk_widgethandler.h
+++ b/fpdfsdk/cpdfsdk_widgethandler.h
@@ -38,6 +38,7 @@ class CPDFSDK_WidgetHandler : public IPDFSDK_AnnotHandler {
void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
CPDFSDK_Annot* pAnnot) override;
+ CFX_WideString GetSelectedText(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 5e258bc4e5..53a7740148 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp
@@ -97,6 +97,11 @@ CFX_FloatRect CPDFSDK_XFAWidgetHandler::GetViewBBox(CPDFSDK_PageView* pPageView,
return rcWidget;
}
+CFX_WideString CPDFSDK_XFAWidgetHandler::GetSelectedText(
+ CPDFSDK_Annot* pAnnot) {
+ return CFX_WideString();
+}
+
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 2aea49b366..65e5e452d2 100644
--- a/fpdfsdk/cpdfsdk_xfawidgethandler.h
+++ b/fpdfsdk/cpdfsdk_xfawidgethandler.h
@@ -33,6 +33,7 @@ class CPDFSDK_XFAWidgetHandler : public IPDFSDK_AnnotHandler {
void ReleaseAnnot(CPDFSDK_Annot* pAnnot) override;
CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
CPDFSDK_Annot* pAnnot) override;
+ CFX_WideString GetSelectedText(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 297d5b78d6..526f4b947d 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_formfiller.cpp
@@ -239,6 +239,17 @@ bool CFFL_FormFiller::OnChar(CPDFSDK_Annot* pAnnot,
return false;
}
+CFX_WideString CFFL_FormFiller::GetSelectedText(CPDFSDK_Annot* pAnnot) {
+ if (!IsValid())
+ return CFX_WideString();
+
+ CPDFSDK_PageView* pPageView = GetCurPageView(true);
+ ASSERT(pPageView);
+
+ CPWL_Wnd* pWnd = GetPDFWindow(pPageView, false);
+ return pWnd ? pWnd->GetSelectedText() : CFX_WideString();
+}
+
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 445e86fb3c..2ddbdf2d6e 100644
--- a/fpdfsdk/formfiller/cffl_formfiller.h
+++ b/fpdfsdk/formfiller/cffl_formfiller.h
@@ -74,6 +74,8 @@ class CFFL_FormFiller : public IPWL_Provider, public CPWL_TimerHandler {
uint32_t nFlags);
virtual bool OnChar(CPDFSDK_Annot* pAnnot, uint32_t nChar, uint32_t nFlags);
+ CFX_WideString GetSelectedText(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 7647fb19ff..69c74bc587 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -522,6 +522,13 @@ void CFFL_InteractiveFormFiller::RemoveFormFiller(CPDFSDK_Annot* pAnnot) {
UnRegisterFormFiller(pAnnot);
}
+CFX_WideString CFFL_InteractiveFormFiller::GetSelectedText(
+ CPDFSDK_Annot* pAnnot) {
+ ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
+ CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
+ return pFormFiller ? pFormFiller->GetSelectedText(pAnnot) : CFX_WideString();
+}
+
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 f72dfbcc61..b7724a32e3 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.h
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.h
@@ -82,6 +82,8 @@ class CFFL_InteractiveFormFiller : public IPWL_Filler_Notify {
CFFL_FormFiller* GetFormFiller(CPDFSDK_Annot* pAnnot, bool bRegister);
void RemoveFormFiller(CPDFSDK_Annot* pAnnot);
+ CFX_WideString GetSelectedText(CPDFSDK_Annot* pAnnot);
+
static bool IsVisible(CPDFSDK_Widget* pWidget);
static bool IsReadOnly(CPDFSDK_Widget* pWidget);
static bool IsFillingAllowed(CPDFSDK_Widget* pWidget);
diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp
index 717e9722af..08d3d30847 100644
--- a/fpdfsdk/fpdfformfill.cpp
+++ b/fpdfsdk/fpdfformfill.cpp
@@ -369,6 +369,24 @@ DLLEXPORT FPDF_BOOL STDCALL FORM_OnChar(FPDF_FORMHANDLE hHandle,
return pPageView->OnChar(nChar, modifier);
}
+DLLEXPORT unsigned long STDCALL FORM_GetSelectedText(FPDF_FORMHANDLE hHandle,
+ FPDF_PAGE page,
+ void* buffer,
+ unsigned long buflen) {
+ CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page);
+ if (!pPageView)
+ return 0;
+
+ CFX_WideString wide_str_form_text = pPageView->GetSelectedText();
+ CFX_ByteString encoded_form_text = wide_str_form_text.UTF16LE_Encode();
+ unsigned long form_text_len = encoded_form_text.GetLength();
+
+ if (buffer && buflen >= form_text_len)
+ memcpy(buffer, encoded_form_text.c_str(), form_text_len);
+
+ return form_text_len;
+}
+
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 8718a43d83..f3043983c2 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -4,10 +4,13 @@
#include <memory>
#include <string>
+#include <vector>
+#include "core/fxcrt/fx_string.h"
#include "core/fxcrt/fx_system.h"
#include "public/cpp/fpdf_deleters.h"
#include "public/fpdf_formfill.h"
+#include "public/fpdf_fwlevent.h"
#include "testing/embedder_test.h"
#include "testing/embedder_test_mock_delegate.h"
#include "testing/embedder_test_timer_handling_delegate.h"
@@ -17,7 +20,78 @@
using testing::_;
using testing::Return;
-class FPDFFormFillEmbeddertest : public EmbedderTest, public TestSaver {};
+class FPDFFormFillEmbeddertest : public EmbedderTest, public TestSaver {
+ protected:
+ void TypeTextIntoTextfield(FPDF_PAGE page, int num_chars) {
+ // Click on the textfield in text_form.pdf.
+ EXPECT_EQ(FPDF_FORMFIELD_TEXTFIELD,
+ FPDFPage_HasFormFieldAtPoint(form_handle(), page, 120.0, 120.0));
+ FORM_OnMouseMove(form_handle(), page, 0, 120.0, 120.0);
+ FORM_OnLButtonDown(form_handle(), page, 0, 120.0, 120.0);
+ FORM_OnLButtonUp(form_handle(), page, 0, 120.0, 120.0);
+
+ // Type text starting with 'A' to as many chars as specified by |num_chars|.
+ for (int i = 0; i < num_chars; ++i) {
+ FORM_OnChar(form_handle(), page, 'A' + i, 0);
+ }
+ }
+
+ // Navigates to form text field using the mouse and then selects text via the
+ // shift and specfied left or right arrow key.
+ void SelectTextWithKeyboard(FPDF_PAGE page,
+ int num_chars,
+ int arrow_key,
+ double x,
+ double y) {
+ // Navigate to starting position for selection.
+ FORM_OnMouseMove(form_handle(), page, 0, x, y);
+ FORM_OnLButtonDown(form_handle(), page, 0, x, y);
+ FORM_OnLButtonUp(form_handle(), page, 0, x, y);
+
+ // Hold down shift (and don't release until entire text is selected).
+ FORM_OnKeyDown(form_handle(), page, FWL_VKEY_Shift, 0);
+
+ // Select text char by char via left or right arrow key.
+ for (int i = 0; i < num_chars; ++i) {
+ FORM_OnKeyDown(form_handle(), page, arrow_key, FWL_EVENTFLAG_ShiftKey);
+ FORM_OnKeyUp(form_handle(), page, arrow_key, FWL_EVENTFLAG_ShiftKey);
+ }
+ FORM_OnKeyUp(form_handle(), page, FWL_VKEY_Shift, 0);
+ }
+
+ // Uses the mouse to navigate to form text field and select text.
+ void SelectTextWithMouse(FPDF_PAGE page,
+ double start_x,
+ double end_x,
+ double y) {
+ // Navigate to starting position and click mouse.
+ FORM_OnMouseMove(form_handle(), page, 0, start_x, y);
+ FORM_OnLButtonDown(form_handle(), page, 0, start_x, y);
+
+ // Hold down mouse until reach end of desired selection.
+ FORM_OnMouseMove(form_handle(), page, 0, end_x, y);
+ FORM_OnLButtonUp(form_handle(), page, 0, end_x, y);
+ }
+
+ void CheckSelection(FPDF_PAGE page, const CFX_WideString& expected_string) {
+ // Calculate expected length for selected text.
+ int num_chars = expected_string.GetLength();
+
+ // Check actual selection against expected selection.
+ const unsigned long expected_length =
+ sizeof(unsigned short) * (num_chars + 1);
+ unsigned long sel_text_len =
+ FORM_GetSelectedText(form_handle(), page, nullptr, 0);
+ ASSERT_EQ(expected_length, sel_text_len);
+
+ std::vector<unsigned short> buf(sel_text_len);
+ EXPECT_EQ(expected_length, FORM_GetSelectedText(form_handle(), page,
+ buf.data(), sel_text_len));
+
+ EXPECT_EQ(expected_string,
+ CFX_WideString::FromUTF16LE(buf.data(), num_chars));
+ }
+};
TEST_F(FPDFFormFillEmbeddertest, FirstTest) {
EmbedderTestMockDelegate mock;
@@ -282,3 +356,100 @@ TEST_F(FPDFFormFillEmbeddertest, FormText) {
RenderPage(new_page.get()));
CompareBitmap(new_bitmap.get(), 300, 300, md5_3);
}
+
+TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextEmptyAndBasicKeyboard) {
+ // Open file with form text field.
+ EXPECT_TRUE(OpenDocument("text_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ // Test empty selection.
+ CheckSelection(page, CFX_WideString(L""));
+
+ // Test basic selection.
+ TypeTextIntoTextfield(page, 3);
+ SelectTextWithKeyboard(page, 3, FWL_VKEY_Left, 123.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"ABC"));
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextEmptyAndBasicMouse) {
+ // Open file with form text field.
+ EXPECT_TRUE(OpenDocument("text_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ // Test empty selection.
+ CheckSelection(page, CFX_WideString(L""));
+
+ // Test basic selection.
+ TypeTextIntoTextfield(page, 3);
+ SelectTextWithMouse(page, 125.0, 102.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"ABC"));
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextFragmentsKeyBoard) {
+ // Open file with form text field.
+ EXPECT_TRUE(OpenDocument("text_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ TypeTextIntoTextfield(page, 12);
+
+ // Test selecting first character in forward direction.
+ // Navigate to starting position and click mouse.
+ SelectTextWithKeyboard(page, 1, FWL_VKEY_Right, 102.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"A"));
+
+ // Test selecting entire long string in backwards direction.
+ SelectTextWithKeyboard(page, 12, FWL_VKEY_Left, 191.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
+
+ // Test selecting middle section in backwards direction.
+ SelectTextWithKeyboard(page, 6, FWL_VKEY_Left, 170.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+ // Test selecting middle selection in forward direction.
+ SelectTextWithKeyboard(page, 6, FWL_VKEY_Right, 125.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+ // Test selecting last character in backwards direction.
+ SelectTextWithKeyboard(page, 1, FWL_VKEY_Left, 191.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"L"));
+
+ UnloadPage(page);
+}
+
+TEST_F(FPDFFormFillEmbeddertest, GetSelectedTextFragmentsMouse) {
+ // Open file with form text field.
+ EXPECT_TRUE(OpenDocument("text_form.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ TypeTextIntoTextfield(page, 12);
+
+ // Test selecting first character in forward direction.
+ SelectTextWithMouse(page, 102.0, 106.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"A"));
+
+ // Test selecting entire long string in backwards direction.
+ SelectTextWithMouse(page, 191.0, 102.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"ABCDEFGHIJKL"));
+
+ // Test selecting middle section in backwards direction.
+ SelectTextWithMouse(page, 170.0, 125.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+ // Test selecting middle selection in forward direction.
+ SelectTextWithMouse(page, 125.0, 170.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"DEFGHI"));
+
+ // Test selecting last character in backwards direction.
+ SelectTextWithMouse(page, 191.0, 186.0, 115.5);
+ CheckSelection(page, CFX_WideString(L"L"));
+
+ UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 0deaf9db1e..05242c6fe1 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -156,6 +156,7 @@ int CheckPDFiumCApi() {
CHK(FORM_OnKeyDown);
CHK(FORM_OnKeyUp);
CHK(FORM_OnChar);
+ CHK(FORM_GetSelectedText);
CHK(FORM_ForceToKillFocus);
CHK(FPDFPage_HasFormFieldAtPoint);
CHK(FPDFPage_FormFieldZOrderAtPoint);
diff --git a/fpdfsdk/ipdfsdk_annothandler.h b/fpdfsdk/ipdfsdk_annothandler.h
index 636d161fea..08008eb996 100644
--- a/fpdfsdk/ipdfsdk_annothandler.h
+++ b/fpdfsdk/ipdfsdk_annothandler.h
@@ -36,6 +36,7 @@ class IPDFSDK_AnnotHandler {
virtual void ReleaseAnnot(CPDFSDK_Annot* pAnnot) = 0;
virtual CFX_FloatRect GetViewBBox(CPDFSDK_PageView* pPageView,
CPDFSDK_Annot* pAnnot) = 0;
+ virtual CFX_WideString GetSelectedText(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 b69f98906e..2929aac90f 100644
--- a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp
@@ -216,6 +216,13 @@ void CPWL_ComboBox::KillFocus() {
CPWL_Wnd::KillFocus();
}
+CFX_WideString CPWL_ComboBox::GetSelectedText() {
+ if (m_pEdit)
+ return m_pEdit->GetSelectedText();
+
+ return CFX_WideString();
+}
+
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 e814ca5d40..549374f3e8 100644
--- a/fpdfsdk/pdfwindow/cpwl_combo_box.h
+++ b/fpdfsdk/pdfwindow/cpwl_combo_box.h
@@ -69,6 +69,7 @@ class CPWL_ComboBox : public CPWL_Wnd {
CFX_FloatRect GetFocusRect() const override;
void SetFocus() override;
void KillFocus() override;
+ CFX_WideString GetSelectedText() override;
void SetFillerNotify(IPWL_Filler_Notify* pNotify);
diff --git a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
index 9c22cead58..3390696e01 100644
--- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp
@@ -53,6 +53,13 @@ void CPWL_EditCtrl::SetCursor() {
}
}
+CFX_WideString CPWL_EditCtrl::GetSelectedText() {
+ if (m_pEdit)
+ return m_pEdit->GetSelText();
+
+ return CFX_WideString();
+}
+
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 59bb623776..1c4c92507a 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 {
void SetFontSize(float fFontSize) override;
float GetFontSize() const override;
void SetCursor() override;
+ CFX_WideString GetSelectedText() override;
void IOnSetScrollInfoY(float fPlateMin,
float fPlateMax,
diff --git a/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp b/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
index 4a14b65d0d..e206cd16e3 100644
--- a/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_edit_embeddertest.cpp
@@ -11,51 +11,115 @@
#include "testing/embedder_test.h"
#include "testing/gtest/include/gtest/gtest.h"
-class CPWLEditEmbeddertest : public EmbedderTest {};
+class CPWLEditEmbeddertest : public EmbedderTest {
+ protected:
+ void SetUp() override {
+ EmbedderTest::SetUp();
+ CreateAndInitializeFormPDF();
+ }
-TEST_F(CPWLEditEmbeddertest, TypeText) {
- EXPECT_TRUE(OpenDocument("text_form.pdf"));
- FPDF_PAGE page = LoadPage(0);
- ASSERT_TRUE(page);
-
- CPDFSDK_FormFillEnvironment* pFormFillEnv =
- static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
-
- CPDFSDK_Annot* pAnnot;
- {
- CBA_AnnotIterator iter(pFormFillEnv->GetPageView(0),
- CPDF_Annot::Subtype::WIDGET);
- pAnnot = iter.GetFirstAnnot();
- CPDFSDK_Annot* pLastAnnot = iter.GetLastAnnot();
- ASSERT_EQ(pAnnot, pLastAnnot);
- ASSERT_TRUE(pAnnot);
- ASSERT_EQ(CPDF_Annot::Subtype::WIDGET, pAnnot->GetAnnotSubtype());
+ void TearDown() override {
+ UnloadPage(GetPage());
+ EmbedderTest::TearDown();
}
- CFFL_InteractiveFormFiller* pInteractiveFormFiller =
- pFormFillEnv->GetInteractiveFormFiller();
- {
- CPDFSDK_Annot::ObservedPtr pObserved(pAnnot);
- EXPECT_TRUE(pInteractiveFormFiller->OnSetFocus(&pObserved, 0));
+ void CreateAndInitializeFormPDF() {
+ EXPECT_TRUE(OpenDocument("text_form.pdf"));
+ m_page = LoadPage(0);
+ ASSERT_TRUE(m_page);
+
+ CPDFSDK_FormFillEnvironment* pFormFillEnv =
+ static_cast<CPDFSDK_FormFillEnvironment*>(form_handle());
+
+ {
+ 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());
+ }
+
+ CFFL_InteractiveFormFiller* pInteractiveFormFiller =
+ pFormFillEnv->GetInteractiveFormFiller();
+ {
+ CPDFSDK_Annot::ObservedPtr pObserved(m_pAnnot);
+ EXPECT_TRUE(pInteractiveFormFiller->OnSetFocus(&pObserved, 0));
+ }
+
+ m_pFormFiller = pInteractiveFormFiller->GetFormFiller(m_pAnnot, false);
+ ASSERT_TRUE(m_pFormFiller);
+
+ CPWL_Wnd* pWindow =
+ m_pFormFiller->GetPDFWindow(pFormFillEnv->GetPageView(0), false);
+ ASSERT_TRUE(pWindow);
+ ASSERT_EQ(PWL_CLASSNAME_EDIT, pWindow->GetClassName());
+
+ m_pEdit = static_cast<CPWL_Edit*>(pWindow);
}
- CFFL_FormFiller* pFormFiller =
- pInteractiveFormFiller->GetFormFiller(pAnnot, false);
- ASSERT_TRUE(pFormFiller);
+ FPDF_PAGE GetPage() { return m_page; }
+ CPWL_Edit* GetCPWLEdit() { return m_pEdit; }
+ CFFL_FormFiller* GetCFFLFormFiller() { return m_pFormFiller; }
+ CPDFSDK_Annot* GetCPDFSDKAnnot() { return m_pAnnot; }
+
+ private:
+ FPDF_PAGE m_page;
+ CPWL_Edit* m_pEdit;
+ CFFL_FormFiller* m_pFormFiller;
+ CPDFSDK_Annot* m_pAnnot;
+};
+
+TEST_F(CPWLEditEmbeddertest, TypeText) {
+ EXPECT_TRUE(GetCPWLEdit()->GetText().IsEmpty());
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'a', 0));
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'b', 0));
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'c', 0));
+
+ EXPECT_STREQ(L"abc", GetCPWLEdit()->GetText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, GetSelectedTextEmptyAndBasic) {
+ // Attempt to set selection before text has been typed to test that
+ // selection is identified as empty.
+ //
+ // Select from character index [0, 3) within form text field.
+ GetCPWLEdit()->SetSel(0, 3);
+ EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
+
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'a', 0));
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'b', 0));
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), 'c', 0));
+ GetCPWLEdit()->SetSel(0, 2);
+
+ EXPECT_STREQ(L"ab", GetCPWLEdit()->GetSelectedText().c_str());
+}
+
+TEST_F(CPWLEditEmbeddertest, GetSelectedTextFragments) {
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_TRUE(GetCFFLFormFiller()->OnChar(GetCPDFSDKAnnot(), i + 'A', 0));
+ }
+
+ GetCPWLEdit()->SetSel(0, 0);
+ EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
+
+ GetCPWLEdit()->SetSel(0, 1);
+ EXPECT_STREQ(L"A", GetCPWLEdit()->GetSelectedText().c_str());
- CPWL_Wnd* pWindow =
- pFormFiller->GetPDFWindow(pFormFillEnv->GetPageView(0), false);
- ASSERT_TRUE(pWindow);
- ASSERT_EQ(PWL_CLASSNAME_EDIT, pWindow->GetClassName());
+ GetCPWLEdit()->SetSel(0, -1);
+ EXPECT_STREQ(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr",
+ GetCPWLEdit()->GetSelectedText().c_str());
- CPWL_Edit* pEdit = static_cast<CPWL_Edit*>(pWindow);
- EXPECT_TRUE(pEdit->GetText().IsEmpty());
+ GetCPWLEdit()->SetSel(-8, -1);
+ EXPECT_TRUE(GetCPWLEdit()->GetSelectedText().IsEmpty());
- EXPECT_TRUE(pFormFiller->OnChar(pAnnot, 'a', 0));
- EXPECT_TRUE(pFormFiller->OnChar(pAnnot, 'b', 0));
- EXPECT_TRUE(pFormFiller->OnChar(pAnnot, 'c', 0));
+ GetCPWLEdit()->SetSel(23, 12);
+ EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
- EXPECT_STREQ(L"abc", pEdit->GetText().c_str());
+ GetCPWLEdit()->SetSel(12, 23);
+ EXPECT_STREQ(L"MNOPQRSTUVW", GetCPWLEdit()->GetSelectedText().c_str());
- UnloadPage(page);
+ GetCPWLEdit()->SetSel(49, 50);
+ EXPECT_STREQ(L"r", GetCPWLEdit()->GetSelectedText().c_str());
}
diff --git a/fpdfsdk/pdfwindow/cpwl_wnd.cpp b/fpdfsdk/pdfwindow/cpwl_wnd.cpp
index 90a79305eb..d44b219110 100644
--- a/fpdfsdk/pdfwindow/cpwl_wnd.cpp
+++ b/fpdfsdk/pdfwindow/cpwl_wnd.cpp
@@ -390,6 +390,10 @@ PWL_IMPLEMENT_MOUSE_METHOD(OnRButtonUp)
PWL_IMPLEMENT_MOUSE_METHOD(OnMouseMove)
#undef PWL_IMPLEMENT_MOUSE_METHOD
+CFX_WideString CPWL_Wnd::GetSelectedText() {
+ return CFX_WideString();
+}
+
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 e7a4e23c38..704984932b 100644
--- a/fpdfsdk/pdfwindow/cpwl_wnd.h
+++ b/fpdfsdk/pdfwindow/cpwl_wnd.h
@@ -229,6 +229,7 @@ class CPWL_Wnd : public CPWL_TimerHandler {
virtual void SetFontSize(float fFontSize);
virtual float GetFontSize() const;
+ virtual CFX_WideString GetSelectedText();
virtual CFX_FloatRect GetFocusRect() const;
virtual CFX_FloatRect GetClientRect() const;
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index caefad78c7..5a15cd9a02 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -1355,6 +1355,29 @@ DLLEXPORT FPDF_BOOL STDCALL FORM_OnChar(FPDF_FORMHANDLE hHandle,
int modifier);
/**
+ * Function: FORM_GetSelectedText
+ * You can call this function to obtain selected text within
+ * a form text field or form combobox text field.
+ * Parameters:
+ * hHandle - Handle to the form fill module. Returned by
+ * FPDFDOC_InitFormFillEnvironment.
+ * page - Handle to the page. Returned by FPDF_LoadPage
+ * function.
+ * buffer - Buffer for holding the selected text, encoded
+ * in UTF16-LE. If NULL, |buffer| is not modified.
+ * buflen - Length of |buffer| in bytes. If |buflen|
+ is less than the length of the selected text
+ string, |buffer| is not modified.
+ * Return Value:
+ * Length in bytes of selected text in form text field or form combobox
+ * text field.
+ **/
+DLLEXPORT unsigned long STDCALL FORM_GetSelectedText(FPDF_FORMHANDLE hHandle,
+ FPDF_PAGE page,
+ void* buffer,
+ unsigned long buflen);
+
+/**
* Function: FORM_ForceToKillFocus.
* You can call this member function to force to kill the focus of the
*form field which got focus.