| // Copyright 2014 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. | 
 |  | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "fpdfsdk/formfiller/cffl_textfield.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "constants/ascii.h" | 
 | #include "constants/form_flags.h" | 
 | #include "core/fpdfdoc/cpdf_bafontmap.h" | 
 | #include "fpdfsdk/cpdfsdk_widget.h" | 
 | #include "fpdfsdk/formfiller/cffl_perwindowdata.h" | 
 | #include "fpdfsdk/pwl/cpwl_edit.h" | 
 | #include "public/fpdf_fwlevent.h" | 
 | #include "third_party/base/check.h" | 
 |  | 
 | namespace { | 
 |  | 
 | // PDF 1.7 spec, Table 8.25 | 
 | enum Alignment { | 
 |   kLeft = 0, | 
 |   kCenter = 1, | 
 |   kRight = 2, | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | CFFL_TextField::CFFL_TextField(CFFL_InteractiveFormFiller* pFormFiller, | 
 |                                CPDFSDK_Widget* pWidget) | 
 |     : CFFL_TextObject(pFormFiller, pWidget) {} | 
 |  | 
 | CFFL_TextField::~CFFL_TextField() { | 
 |   // See comment in cffl_formfiller.h. | 
 |   // The font map should be stored somewhere more appropriate so it will live | 
 |   // until the PWL_Edit is done with it. pdfium:566 | 
 |   DestroyWindows(); | 
 | } | 
 |  | 
 | CPWL_Wnd::CreateParams CFFL_TextField::GetCreateParam() { | 
 |   CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam(); | 
 |   int nFlags = m_pWidget->GetFieldFlags(); | 
 |   if (nFlags & pdfium::form_flags::kTextPassword) | 
 |     cp.dwFlags |= PES_PASSWORD; | 
 |  | 
 |   if (nFlags & pdfium::form_flags::kTextMultiline) { | 
 |     cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP; | 
 |     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll)) | 
 |       cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL; | 
 |   } else { | 
 |     cp.dwFlags |= PES_CENTER; | 
 |     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll)) | 
 |       cp.dwFlags |= PES_AUTOSCROLL; | 
 |   } | 
 |  | 
 |   if (nFlags & pdfium::form_flags::kTextComb) | 
 |     cp.dwFlags |= PES_CHARARRAY; | 
 |  | 
 |   if (nFlags & pdfium::form_flags::kTextRichText) | 
 |     cp.dwFlags |= PES_RICH; | 
 |  | 
 |   cp.dwFlags |= PES_UNDO; | 
 |  | 
 |   switch (m_pWidget->GetAlignment()) { | 
 |     default: | 
 |     case kLeft: | 
 |       cp.dwFlags |= PES_LEFT; | 
 |       break; | 
 |     case kCenter: | 
 |       cp.dwFlags |= PES_MIDDLE; | 
 |       break; | 
 |     case kRight: | 
 |       cp.dwFlags |= PES_RIGHT; | 
 |       break; | 
 |   } | 
 |   cp.pFontMap = GetOrCreateFontMap(); | 
 |   return cp; | 
 | } | 
 |  | 
 | std::unique_ptr<CPWL_Wnd> CFFL_TextField::NewPWLWindow( | 
 |     const CPWL_Wnd::CreateParams& cp, | 
 |     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData) { | 
 |   static_cast<CFFL_PerWindowData*>(pAttachedData.get())->SetFormField(this); | 
 |   auto pWnd = std::make_unique<CPWL_Edit>(cp, std::move(pAttachedData)); | 
 |   pWnd->Realize(); | 
 |  | 
 |   int32_t nMaxLen = m_pWidget->GetMaxLen(); | 
 |   WideString swValue = m_pWidget->GetValue(); | 
 |   if (nMaxLen > 0) { | 
 |     if (pWnd->HasFlag(PES_CHARARRAY)) { | 
 |       pWnd->SetCharArray(nMaxLen); | 
 |       pWnd->SetAlignFormatVerticalCenter(); | 
 |     } else { | 
 |       pWnd->SetLimitChar(nMaxLen); | 
 |     } | 
 |   } | 
 |   pWnd->SetText(swValue); | 
 |   return std::move(pWnd); | 
 | } | 
 |  | 
 | bool CFFL_TextField::OnChar(CPDFSDK_Widget* pWidget, | 
 |                             uint32_t nChar, | 
 |                             Mask<FWL_EVENTFLAG> nFlags) { | 
 |   switch (nChar) { | 
 |     case pdfium::ascii::kReturn: { | 
 |       if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kTextMultiline) | 
 |         break; | 
 |  | 
 |       CPDFSDK_PageView* pPageView = GetCurPageView(); | 
 |       DCHECK(pPageView); | 
 |       m_bValid = !m_bValid; | 
 |       m_pFormFiller->GetCallbackIface()->Invalidate( | 
 |           pWidget->GetPage(), pWidget->GetRect().GetOuterRect()); | 
 |       if (m_bValid) { | 
 |         if (CPWL_Wnd* pWnd = CreateOrUpdatePWLWindow(pPageView)) | 
 |           pWnd->SetFocus(); | 
 |         break; | 
 |       } | 
 |  | 
 |       if (!CommitData(pPageView, nFlags)) | 
 |         return false; | 
 |  | 
 |       DestroyPWLWindow(pPageView); | 
 |       return true; | 
 |     } | 
 |     case pdfium::ascii::kEscape: { | 
 |       CPDFSDK_PageView* pPageView = GetCurPageView(); | 
 |       DCHECK(pPageView); | 
 |       EscapeFiller(pPageView, true); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   return CFFL_TextObject::OnChar(pWidget, nChar, nFlags); | 
 | } | 
 |  | 
 | bool CFFL_TextField::IsDataChanged(const CPDFSDK_PageView* pPageView) { | 
 |   CPWL_Edit* pEdit = GetPWLEdit(pPageView); | 
 |   return pEdit && pEdit->GetText() != m_pWidget->GetValue(); | 
 | } | 
 |  | 
 | void CFFL_TextField::SaveData(const CPDFSDK_PageView* pPageView) { | 
 |   CPWL_Edit* pWnd = GetPWLEdit(pPageView); | 
 |   if (!pWnd) | 
 |     return; | 
 |  | 
 |   WideString sOldValue = m_pWidget->GetValue(); | 
 |   WideString sNewValue = pWnd->GetText(); | 
 |   ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget.Get()); | 
 |   ObservedPtr<CFFL_TextField> observed_this(this); | 
 |   m_pWidget->SetValue(sNewValue); | 
 |   if (!observed_widget) | 
 |     return; | 
 |  | 
 |   m_pWidget->ResetFieldAppearance(); | 
 |   if (!observed_widget) | 
 |     return; | 
 |  | 
 |   m_pWidget->UpdateField(); | 
 |   if (!observed_widget || !observed_this) | 
 |     return; | 
 |  | 
 |   SetChangeMark(); | 
 | } | 
 |  | 
 | void CFFL_TextField::GetActionData(const CPDFSDK_PageView* pPageView, | 
 |                                    CPDF_AAction::AActionType type, | 
 |                                    CFFL_FieldAction& fa) { | 
 |   switch (type) { | 
 |     case CPDF_AAction::kKeyStroke: | 
 |       if (CPWL_Edit* pWnd = GetPWLEdit(pPageView)) { | 
 |         fa.bFieldFull = pWnd->IsTextFull(); | 
 |  | 
 |         fa.sValue = pWnd->GetText(); | 
 |  | 
 |         if (fa.bFieldFull) { | 
 |           fa.sChange.clear(); | 
 |           fa.sChangeEx.clear(); | 
 |         } | 
 |       } | 
 |       break; | 
 |     case CPDF_AAction::kValidate: | 
 |       if (CPWL_Edit* pWnd = GetPWLEdit(pPageView)) { | 
 |         fa.sValue = pWnd->GetText(); | 
 |       } | 
 |       break; | 
 |     case CPDF_AAction::kLoseFocus: | 
 |     case CPDF_AAction::kGetFocus: | 
 |       fa.sValue = m_pWidget->GetValue(); | 
 |       break; | 
 |     default: | 
 |       break; | 
 |   } | 
 | } | 
 |  | 
 | void CFFL_TextField::SetActionData(const CPDFSDK_PageView* pPageView, | 
 |                                    CPDF_AAction::AActionType type, | 
 |                                    const CFFL_FieldAction& fa) { | 
 |   switch (type) { | 
 |     case CPDF_AAction::kKeyStroke: | 
 |       if (CPWL_Edit* pEdit = GetPWLEdit(pPageView)) { | 
 |         pEdit->SetFocus(); | 
 |         pEdit->SetSelection(fa.nSelStart, fa.nSelEnd); | 
 |         pEdit->ReplaceSelection(fa.sChange); | 
 |       } | 
 |       break; | 
 |     default: | 
 |       break; | 
 |   } | 
 | } | 
 |  | 
 | void CFFL_TextField::SavePWLWindowState(const CPDFSDK_PageView* pPageView) { | 
 |   CPWL_Edit* pWnd = GetPWLEdit(pPageView); | 
 |   if (!pWnd) | 
 |     return; | 
 |  | 
 |   std::tie(m_State.nStart, m_State.nEnd) = pWnd->GetSelection(); | 
 |   m_State.sValue = pWnd->GetText(); | 
 | } | 
 |  | 
 | void CFFL_TextField::RecreatePWLWindowFromSavedState( | 
 |     const CPDFSDK_PageView* pPageView) { | 
 |   CPWL_Edit* pWnd = CreateOrUpdatePWLEdit(pPageView); | 
 |   if (!pWnd) | 
 |     return; | 
 |  | 
 |   pWnd->SetText(m_State.sValue); | 
 |   pWnd->SetSelection(m_State.nStart, m_State.nEnd); | 
 | } | 
 |  | 
 | #ifdef PDF_ENABLE_XFA | 
 | bool CFFL_TextField::IsFieldFull(const CPDFSDK_PageView* pPageView) { | 
 |   CPWL_Edit* pWnd = GetPWLEdit(pPageView); | 
 |   return pWnd && pWnd->IsTextFull(); | 
 | } | 
 | #endif  // PDF_ENABLE_XFA | 
 |  | 
 | void CFFL_TextField::OnSetFocusForEdit(CPWL_Edit* pEdit) { | 
 |   pEdit->SetCharSet(FX_Charset::kChineseSimplified); | 
 |   pEdit->SetReadyToInput(); | 
 |   m_pFormFiller->GetCallbackIface()->OnSetFieldInputFocus(pEdit->GetText()); | 
 | } | 
 |  | 
 | CPWL_Edit* CFFL_TextField::GetPWLEdit(const CPDFSDK_PageView* pPageView) const { | 
 |   return static_cast<CPWL_Edit*>(GetPWLWindow(pPageView)); | 
 | } | 
 |  | 
 | CPWL_Edit* CFFL_TextField::CreateOrUpdatePWLEdit( | 
 |     const CPDFSDK_PageView* pPageView) { | 
 |   return static_cast<CPWL_Edit*>(CreateOrUpdatePWLWindow(pPageView)); | 
 | } |