• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fpdfsdk/formfiller/cffl_textfield.h"
8 
9 #include <utility>
10 
11 #include "constants/form_flags.h"
12 #include "core/fpdfdoc/cba_fontmap.h"
13 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
14 #include "fpdfsdk/cpdfsdk_widget.h"
15 #include "public/fpdf_fwlevent.h"
16 #include "third_party/base/ptr_util.h"
17 
18 namespace {
19 
20 // PDF 1.7 spec, Table 8.25
21 enum Alignment {
22   kLeft = 0,
23   kCenter = 1,
24   kRight = 2,
25 };
26 
27 }  // namespace
28 
CFFL_TextField(CPDFSDK_FormFillEnvironment * pApp,CPDFSDK_Widget * pWidget)29 CFFL_TextField::CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp,
30                                CPDFSDK_Widget* pWidget)
31     : CFFL_TextObject(pApp, pWidget) {}
32 
~CFFL_TextField()33 CFFL_TextField::~CFFL_TextField() {
34   for (const auto& it : m_Maps)
35     it.second->InvalidateFocusHandler(this);
36 
37   // See comment in cffl_formfiller.h.
38   // The font map should be stored somewhere more appropriate so it will live
39   // until the PWL_Edit is done with it. pdfium:566
40   DestroyWindows();
41 }
42 
GetCreateParam()43 CPWL_Wnd::CreateParams CFFL_TextField::GetCreateParam() {
44   CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
45   int nFlags = m_pWidget->GetFieldFlags();
46   if (nFlags & pdfium::form_flags::kTextPassword)
47     cp.dwFlags |= PES_PASSWORD;
48 
49   if (nFlags & pdfium::form_flags::kTextMultiline) {
50     cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP;
51     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll))
52       cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL;
53   } else {
54     cp.dwFlags |= PES_CENTER;
55     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll))
56       cp.dwFlags |= PES_AUTOSCROLL;
57   }
58 
59   if (nFlags & pdfium::form_flags::kTextComb)
60     cp.dwFlags |= PES_CHARARRAY;
61 
62   if (nFlags & pdfium::form_flags::kTextRichText)
63     cp.dwFlags |= PES_RICH;
64 
65   cp.dwFlags |= PES_UNDO;
66 
67   switch (m_pWidget->GetAlignment()) {
68     default:
69     case kLeft:
70       cp.dwFlags |= PES_LEFT;
71       break;
72     case kCenter:
73       cp.dwFlags |= PES_MIDDLE;
74       break;
75     case kRight:
76       cp.dwFlags |= PES_RIGHT;
77       break;
78   }
79   cp.pFontMap = MaybeCreateFontMap();
80   cp.pFocusHandler = this;
81   return cp;
82 }
83 
NewPWLWindow(const CPWL_Wnd::CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)84 std::unique_ptr<CPWL_Wnd> CFFL_TextField::NewPWLWindow(
85     const CPWL_Wnd::CreateParams& cp,
86     std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData) {
87   auto pWnd = pdfium::MakeUnique<CPWL_Edit>(cp, std::move(pAttachedData));
88   pWnd->AttachFFLData(this);
89   pWnd->Realize();
90   pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
91 
92   int32_t nMaxLen = m_pWidget->GetMaxLen();
93   WideString swValue = m_pWidget->GetValue();
94   if (nMaxLen > 0) {
95     if (pWnd->HasFlag(PES_CHARARRAY)) {
96       pWnd->SetCharArray(nMaxLen);
97       pWnd->SetAlignFormatVerticalCenter();
98     } else {
99       pWnd->SetLimitChar(nMaxLen);
100     }
101   }
102   pWnd->SetText(swValue);
103   return std::move(pWnd);
104 }
105 
OnChar(CPDFSDK_Annot * pAnnot,uint32_t nChar,uint32_t nFlags)106 bool CFFL_TextField::OnChar(CPDFSDK_Annot* pAnnot,
107                             uint32_t nChar,
108                             uint32_t nFlags) {
109   switch (nChar) {
110     case FWL_VKEY_Return: {
111       if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kTextMultiline)
112         break;
113 
114       CPDFSDK_PageView* pPageView = GetCurPageView(true);
115       ASSERT(pPageView);
116       m_bValid = !m_bValid;
117       m_pFormFillEnv->Invalidate(pAnnot->GetPage(),
118                                  pAnnot->GetRect().GetOuterRect());
119 
120       if (m_bValid) {
121         if (CPWL_Wnd* pWnd = GetPWLWindow(pPageView, true))
122           pWnd->SetFocus();
123         break;
124       }
125 
126       if (!CommitData(pPageView, nFlags))
127         return false;
128 
129       DestroyPWLWindow(pPageView);
130       return true;
131     }
132     case FWL_VKEY_Escape: {
133       CPDFSDK_PageView* pPageView = GetCurPageView(true);
134       ASSERT(pPageView);
135       EscapeFiller(pPageView, true);
136       return true;
137     }
138   }
139 
140   return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
141 }
142 
IsDataChanged(CPDFSDK_PageView * pPageView)143 bool CFFL_TextField::IsDataChanged(CPDFSDK_PageView* pPageView) {
144   CPWL_Edit* pEdit = GetEdit(pPageView, false);
145   return pEdit && pEdit->GetText() != m_pWidget->GetValue();
146 }
147 
SaveData(CPDFSDK_PageView * pPageView)148 void CFFL_TextField::SaveData(CPDFSDK_PageView* pPageView) {
149   CPWL_Edit* pWnd = GetEdit(pPageView, false);
150   if (!pWnd)
151     return;
152 
153   WideString sOldValue = m_pWidget->GetValue();
154   WideString sNewValue = pWnd->GetText();
155   ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget.Get());
156   ObservedPtr<CFFL_TextField> observed_this(this);
157   m_pWidget->SetValue(sNewValue, NotificationOption::kDoNotNotify);
158   if (!observed_widget)
159     return;
160 
161   m_pWidget->ResetFieldAppearance();
162   if (!observed_widget)
163     return;
164 
165   m_pWidget->UpdateField();
166   if (!observed_widget || !observed_this)
167     return;
168 
169   SetChangeMark();
170 }
171 
GetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,CPDFSDK_FieldAction & fa)172 void CFFL_TextField::GetActionData(CPDFSDK_PageView* pPageView,
173                                    CPDF_AAction::AActionType type,
174                                    CPDFSDK_FieldAction& fa) {
175   switch (type) {
176     case CPDF_AAction::kKeyStroke:
177       if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
178         fa.bFieldFull = pWnd->IsTextFull();
179 
180         fa.sValue = pWnd->GetText();
181 
182         if (fa.bFieldFull) {
183           fa.sChange.clear();
184           fa.sChangeEx.clear();
185         }
186       }
187       break;
188     case CPDF_AAction::kValidate:
189       if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
190         fa.sValue = pWnd->GetText();
191       }
192       break;
193     case CPDF_AAction::kLoseFocus:
194     case CPDF_AAction::kGetFocus:
195       fa.sValue = m_pWidget->GetValue();
196       break;
197     default:
198       break;
199   }
200 }
201 
SetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,const CPDFSDK_FieldAction & fa)202 void CFFL_TextField::SetActionData(CPDFSDK_PageView* pPageView,
203                                    CPDF_AAction::AActionType type,
204                                    const CPDFSDK_FieldAction& fa) {
205   switch (type) {
206     case CPDF_AAction::kKeyStroke:
207       if (CPWL_Edit* pEdit = GetEdit(pPageView, false)) {
208         pEdit->SetFocus();
209         pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
210         pEdit->ReplaceSelection(fa.sChange);
211       }
212       break;
213     default:
214       break;
215   }
216 }
217 
SaveState(CPDFSDK_PageView * pPageView)218 void CFFL_TextField::SaveState(CPDFSDK_PageView* pPageView) {
219   CPWL_Edit* pWnd = GetEdit(pPageView, false);
220   if (!pWnd)
221     return;
222 
223   pWnd->GetSelection(m_State.nStart, m_State.nEnd);
224   m_State.sValue = pWnd->GetText();
225 }
226 
RestoreState(CPDFSDK_PageView * pPageView)227 void CFFL_TextField::RestoreState(CPDFSDK_PageView* pPageView) {
228   CPWL_Edit* pWnd = GetEdit(pPageView, true);
229   if (!pWnd)
230     return;
231 
232   pWnd->SetText(m_State.sValue);
233   pWnd->SetSelection(m_State.nStart, m_State.nEnd);
234 }
235 
236 #ifdef PDF_ENABLE_XFA
IsFieldFull(CPDFSDK_PageView * pPageView)237 bool CFFL_TextField::IsFieldFull(CPDFSDK_PageView* pPageView) {
238   CPWL_Edit* pWnd = GetEdit(pPageView, false);
239   return pWnd && pWnd->IsTextFull();
240 }
241 #endif  // PDF_ENABLE_XFA
242 
OnSetFocus(CPWL_Edit * pEdit)243 void CFFL_TextField::OnSetFocus(CPWL_Edit* pEdit) {
244   pEdit->SetCharSet(FX_CHARSET_ChineseSimplified);
245   pEdit->SetReadyToInput();
246 
247   WideString wsText = pEdit->GetText();
248   int nCharacters = wsText.GetLength();
249   ByteString bsUTFText = wsText.ToUTF16LE();
250   auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
251   m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
252 }
253 
GetEdit(CPDFSDK_PageView * pPageView,bool bNew)254 CPWL_Edit* CFFL_TextField::GetEdit(CPDFSDK_PageView* pPageView, bool bNew) {
255   return static_cast<CPWL_Edit*>(GetPWLWindow(pPageView, bNew));
256 }
257