From b8777a2c5f38ea4d6fc74ea01a114d3e056c0fdb Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Wed, 20 Sep 2017 16:21:31 -0400 Subject: Add embeddertest for CFWL_Edit This CL adds two mouse selection tests for CFWL_Edit. In order to do so the needed selection code was added to the XFA widget handler and plumbed down to the CFWL_Edit field as needed. Bug: pdfium:840 Change-Id: Ia3b5f5d191494a4579c01524df8fb35b24cc0085 Reviewed-on: https://pdfium-review.googlesource.com/14530 Reviewed-by: Ryan Harrison Commit-Queue: dsinclair --- BUILD.gn | 1 + fpdfsdk/cpdfsdk_xfawidgethandler.cpp | 18 ++++++---- xfa/fwl/cfwl_edit.cpp | 39 +++++++++++---------- xfa/fwl/cfwl_edit.h | 2 +- xfa/fwl/cfwl_edit_embeddertest.cpp | 67 ++++++++++++++++++++++++++++++++++++ xfa/fxfa/cxfa_fftextedit.cpp | 67 ++++++++++++++++++++++++++++++++++++ xfa/fxfa/cxfa_fftextedit.h | 16 +++++++++ xfa/fxfa/cxfa_ffwidgethandler.cpp | 17 +++++++++ xfa/fxfa/cxfa_ffwidgethandler.h | 3 ++ 9 files changed, 204 insertions(+), 26 deletions(-) create mode 100644 xfa/fwl/cfwl_edit_embeddertest.cpp diff --git a/BUILD.gn b/BUILD.gn index 9c8d221552..2cf6552f21 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -2051,6 +2051,7 @@ test("pdfium_embeddertests") { sources += [ "testing/xfa_js_embedder_test.cpp", "testing/xfa_js_embedder_test.h", + "xfa/fwl/cfwl_edit_embeddertest.cpp", "xfa/fxfa/fm2js/cxfa_fm2jscontext_embeddertest.cpp", "xfa/fxfa/parser/cxfa_simple_parser_embeddertest.cpp", ] diff --git a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp index b5c52a89cc..c1ef2bdb23 100644 --- a/fpdfsdk/cpdfsdk_xfawidgethandler.cpp +++ b/fpdfsdk/cpdfsdk_xfawidgethandler.cpp @@ -97,16 +97,22 @@ CFX_FloatRect CPDFSDK_XFAWidgetHandler::GetViewBBox(CPDFSDK_PageView* pPageView, return rcWidget; } -// TODO(bug 840): Implement so selected text can be obtained from XFA -// fields. WideString CPDFSDK_XFAWidgetHandler::GetSelectedText(CPDFSDK_Annot* pAnnot) { - return WideString(); + if (!pAnnot) + return WideString(); + + CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot); + return pWidgetHandler->GetSelectedText(pAnnot->GetXFAWidget()); } -// TODO(bug 840): Implement so text can be inserted into and deleted from XFA -// fields. void CPDFSDK_XFAWidgetHandler::ReplaceSelection(CPDFSDK_Annot* pAnnot, - const WideString& text) {} + const WideString& text) { + if (!pAnnot) + return; + + CXFA_FFWidgetHandler* pWidgetHandler = GetXFAWidgetHandler(pAnnot); + return pWidgetHandler->PasteText(pAnnot->GetXFAWidget(), text); +} bool CPDFSDK_XFAWidgetHandler::HitTest(CPDFSDK_PageView* pPageView, CPDFSDK_Annot* pAnnot, diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp index 426d46e761..d1f0c99a39 100644 --- a/xfa/fwl/cfwl_edit.cpp +++ b/xfa/fwl/cfwl_edit.cpp @@ -1120,7 +1120,7 @@ void CFWL_Edit::OnProcessMessage(CFWL_Message* pMessage) { OnMouseMove(pMsg); break; case FWL_MouseCommand::RightButtonDown: - DoButtonDown(pMsg); + DoRButtonDown(pMsg); break; default: break; @@ -1159,17 +1159,11 @@ void CFWL_Edit::OnDrawWidget(CXFA_Graphics* pGraphics, DrawWidget(pGraphics, matrix); } -void CFWL_Edit::DoButtonDown(CFWL_MessageMouse* pMsg) { +void CFWL_Edit::DoRButtonDown(CFWL_MessageMouse* pMsg) { if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) SetFocus(true); - // TODO(dsinclair): Handle DoButtonDown - // bool bBefore = true; - // int32_t nIndex = - // std::max(0, pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos), - // bBefore)); - - // SetCursorPosition(nIndex); + m_CursorPosition = m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos)); } void CFWL_Edit::OnFocusChanged(CFWL_Message* pMsg, bool bSet) { @@ -1206,7 +1200,9 @@ void CFWL_Edit::OnLButtonDown(CFWL_MessageMouse* pMsg) { m_bLButtonDown = true; SetGrab(true); - DoButtonDown(pMsg); + + if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) + SetFocus(true); bool bRepaint = false; if (m_EdtEngine.HasSelection()) { @@ -1216,13 +1212,16 @@ void CFWL_Edit::OnLButtonDown(CFWL_MessageMouse* pMsg) { size_t index_at_click = m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos)); + if (index_at_click != m_CursorPosition && !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift)) { size_t start = std::min(m_CursorPosition, index_at_click); size_t end = std::max(m_CursorPosition, index_at_click); - m_EdtEngine.SetSelection(start, end); + m_EdtEngine.SetSelection(start, end - start); bRepaint = true; + } else { + m_CursorPosition = index_at_click; } if (bRepaint) @@ -1259,14 +1258,16 @@ void CFWL_Edit::OnMouseMove(CFWL_MessageMouse* pMsg) { if (m_CursorPosition > length) SetCursorPosition(length); - size_t sel_start; - size_t count; - std::tie(sel_start, count) = m_EdtEngine.GetSelection(); - size_t original_end = sel_start + count; - sel_start = std::min(sel_start, m_CursorPosition); - m_EdtEngine.SetSelection( - std::min(sel_start, m_CursorPosition), - std::max(original_end, m_CursorPosition) - sel_start); + size_t sel_start = 0; + size_t count = 0; + if (m_EdtEngine.HasSelection()) + std::tie(sel_start, count) = m_EdtEngine.GetSelection(); + else + sel_start = old_cursor_pos; + + size_t start_pos = std::min(sel_start, m_CursorPosition); + size_t end_pos = std::max(sel_start, m_CursorPosition); + m_EdtEngine.SetSelection(start_pos, end_pos - start_pos); } void CFWL_Edit::OnKeyDown(CFWL_MessageKey* pMsg) { diff --git a/xfa/fwl/cfwl_edit.h b/xfa/fwl/cfwl_edit.h index cfebb25146..b7c252668b 100644 --- a/xfa/fwl/cfwl_edit.h +++ b/xfa/fwl/cfwl_edit.h @@ -142,7 +142,7 @@ class CFWL_Edit : public CFWL_Widget, public CFDE_TextEditEngine::Delegate { void SetCursorPosition(size_t position); void UpdateCursorRect(); - void DoButtonDown(CFWL_MessageMouse* pMsg); + void DoRButtonDown(CFWL_MessageMouse* pMsg); void OnFocusChanged(CFWL_Message* pMsg, bool bSet); void OnLButtonDown(CFWL_MessageMouse* pMsg); void OnLButtonUp(CFWL_MessageMouse* pMsg); diff --git a/xfa/fwl/cfwl_edit_embeddertest.cpp b/xfa/fwl/cfwl_edit_embeddertest.cpp new file mode 100644 index 0000000000..c1575689eb --- /dev/null +++ b/xfa/fwl/cfwl_edit_embeddertest.cpp @@ -0,0 +1,67 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fxcrt/widestring.h" +#include "public/fpdf_formfill.h" +#include "public/fpdf_fwlevent.h" +#include "testing/embedder_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +class CFWLEditEmbeddertest : public EmbedderTest { + protected: + void SetUp() override { + EmbedderTest::SetUp(); + CreateAndInitializeFormPDF(); + } + + void TearDown() override { + UnloadPage(page()); + EmbedderTest::TearDown(); + } + + void CreateAndInitializeFormPDF() { + EXPECT_TRUE(OpenDocument("xfa/email_recommended.pdf")); + page_ = LoadPage(0); + ASSERT_TRUE(page_); + } + + FPDF_PAGE page() const { return page_; } + + private: + FPDF_PAGE page_; +}; + +TEST_F(CFWLEditEmbeddertest, LeftClickMouseSelection) { + FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58); + for (size_t i = 0; i < 10; ++i) + FORM_OnChar(form_handle(), page(), 'a' + i, 0); + + // Mouse selection + FORM_OnLButtonDown(form_handle(), page(), 0, 128, 58); + FORM_OnLButtonDown(form_handle(), page(), FWL_EVENTFLAG_ShiftKey, 152, 58); + + // 12 == (2 * strlen(defgh)) + 2 (for \0\0) + EXPECT_EQ(12UL, FORM_GetSelectedText(form_handle(), page(), nullptr, 0)); + + unsigned short buf[128]; + unsigned long len = FORM_GetSelectedText(form_handle(), page(), &buf, 128); + EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str()); +} + +TEST_F(CFWLEditEmbeddertest, DragMouseSelection) { + FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58); + for (size_t i = 0; i < 10; ++i) + FORM_OnChar(form_handle(), page(), 'a' + i, 0); + + // Mouse selection + FORM_OnLButtonDown(form_handle(), page(), 0, 128, 58); + FORM_OnMouseMove(form_handle(), page(), FWL_EVENTFLAG_ShiftKey, 152, 58); + + // 12 == (2 * strlen(defgh)) + 2 (for \0\0) + EXPECT_EQ(12UL, FORM_GetSelectedText(form_handle(), page(), nullptr, 0)); + + unsigned short buf[128]; + unsigned long len = FORM_GetSelectedText(form_handle(), page(), &buf, 128); + EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str()); +} diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp index 82b6f63b59..8f68368757 100644 --- a/xfa/fxfa/cxfa_fftextedit.cpp +++ b/xfa/fxfa/cxfa_fftextedit.cpp @@ -20,6 +20,14 @@ #include "xfa/fxfa/cxfa_ffapp.h" #include "xfa/fxfa/parser/cxfa_node.h" +namespace { + +CFWL_Edit* ToEdit(CFWL_Widget* widget) { + return static_cast(widget); +} + +} // namespace + CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_WidgetAcc* pDataAcc) : CXFA_FFField(pDataAcc), m_pOldDelegate(nullptr) {} @@ -356,3 +364,62 @@ void CXFA_FFTextEdit::OnDrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) { m_pOldDelegate->OnDrawWidget(pGraphics, matrix); } + +bool CXFA_FFTextEdit::CanUndo() { + return ToEdit(m_pNormalWidget.get())->CanUndo(); +} + +bool CXFA_FFTextEdit::CanRedo() { + return ToEdit(m_pNormalWidget.get())->CanRedo(); +} + +bool CXFA_FFTextEdit::Undo() { + return ToEdit(m_pNormalWidget.get())->Undo(); +} + +bool CXFA_FFTextEdit::Redo() { + return ToEdit(m_pNormalWidget.get())->Redo(); +} + +bool CXFA_FFTextEdit::CanCopy() { + return ToEdit(m_pNormalWidget.get())->HasSelection(); +} + +bool CXFA_FFTextEdit::CanCut() { + if (ToEdit(m_pNormalWidget.get())->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly) + return false; + return ToEdit(m_pNormalWidget.get())->HasSelection(); +} + +bool CXFA_FFTextEdit::CanPaste() { + return !(ToEdit(m_pNormalWidget.get())->GetStylesEx() & + FWL_STYLEEXT_EDT_ReadOnly); +} + +bool CXFA_FFTextEdit::CanSelectAll() { + return ToEdit(m_pNormalWidget.get())->GetTextLength() > 0; +} + +bool CXFA_FFTextEdit::Copy(WideString& wsCopy) { + return ToEdit(m_pNormalWidget.get())->Copy(wsCopy); +} + +bool CXFA_FFTextEdit::Cut(WideString& wsCut) { + return ToEdit(m_pNormalWidget.get())->Copy(wsCut); +} + +bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) { + return ToEdit(m_pNormalWidget.get())->Paste(wsPaste); +} + +void CXFA_FFTextEdit::SelectAll() { + ToEdit(m_pNormalWidget.get())->SelectAll(); +} + +void CXFA_FFTextEdit::Delete() { + ToEdit(m_pNormalWidget.get())->ClearText(); +} + +void CXFA_FFTextEdit::DeSelect() { + ToEdit(m_pNormalWidget.get())->ClearSelection(); +} diff --git a/xfa/fxfa/cxfa_fftextedit.h b/xfa/fxfa/cxfa_fftextedit.h index 9735b9e7d8..dd3801b4df 100644 --- a/xfa/fxfa/cxfa_fftextedit.h +++ b/xfa/fxfa/cxfa_fftextedit.h @@ -42,6 +42,22 @@ class CXFA_FFTextEdit : public CXFA_FFField { void OnTextFull(CFWL_Widget* pWidget); bool CheckWord(const ByteStringView& sWord); + // CXFA_FFWidget + bool CanUndo() override; + bool CanRedo() override; + bool Undo() override; + bool Redo() override; + bool CanCopy() override; + bool CanCut() override; + bool CanPaste() override; + bool CanSelectAll() override; + bool Copy(WideString& wsCopy) override; + bool Cut(WideString& wsCut) override; + bool Paste(const WideString& wsPaste) override; + void SelectAll() override; + void Delete() override; + void DeSelect() override; + protected: uint32_t GetAlignment(); diff --git a/xfa/fxfa/cxfa_ffwidgethandler.cpp b/xfa/fxfa/cxfa_ffwidgethandler.cpp index 524bbed9e2..8f916d804b 100644 --- a/xfa/fxfa/cxfa_ffwidgethandler.cpp +++ b/xfa/fxfa/cxfa_ffwidgethandler.cpp @@ -142,6 +142,23 @@ bool CXFA_FFWidgetHandler::OnChar(CXFA_FFWidget* hWidget, return bRet; } +WideString CXFA_FFWidgetHandler::GetSelectedText(CXFA_FFWidget* widget) { + if (!widget->CanCopy()) + return WideString(); + + WideString val; + widget->Copy(val); + return val; +} + +void CXFA_FFWidgetHandler::PasteText(CXFA_FFWidget* widget, + const WideString& text) { + if (!widget->CanPaste()) + return; + + widget->Paste(text); +} + FWL_WidgetHit CXFA_FFWidgetHandler::OnHitTest(CXFA_FFWidget* hWidget, const CFX_PointF& point) { if (!(hWidget->GetStatus() & XFA_WidgetStatus_Visible)) diff --git a/xfa/fxfa/cxfa_ffwidgethandler.h b/xfa/fxfa/cxfa_ffwidgethandler.h index 474412069e..e2b50dc27c 100644 --- a/xfa/fxfa/cxfa_ffwidgethandler.h +++ b/xfa/fxfa/cxfa_ffwidgethandler.h @@ -53,6 +53,9 @@ class CXFA_FFWidgetHandler { uint32_t dwFlags, const CFX_PointF& point); + WideString GetSelectedText(CXFA_FFWidget* widget); + void PasteText(CXFA_FFWidget* widget, const WideString& text); + bool OnKeyDown(CXFA_FFWidget* hWidget, uint32_t dwKeyCode, uint32_t dwFlags); bool OnKeyUp(CXFA_FFWidget* hWidget, uint32_t dwKeyCode, uint32_t dwFlags); bool OnChar(CXFA_FFWidget* hWidget, uint32_t dwChar, uint32_t dwFlags); -- cgit v1.2.3