xref: /aosp_15_r20/external/pdfium/fpdfsdk/formfiller/cffl_textfield.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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/ascii.h"
12 #include "constants/form_flags.h"
13 #include "core/fpdfdoc/cpdf_bafontmap.h"
14 #include "fpdfsdk/cpdfsdk_widget.h"
15 #include "fpdfsdk/formfiller/cffl_perwindowdata.h"
16 #include "fpdfsdk/pwl/cpwl_edit.h"
17 #include "public/fpdf_fwlevent.h"
18 #include "third_party/base/check.h"
19 
20 namespace {
21 
22 // PDF 1.7 spec, Table 8.25
23 enum Alignment {
24   kLeft = 0,
25   kCenter = 1,
26   kRight = 2,
27 };
28 
29 }  // namespace
30 
CFFL_TextField(CFFL_InteractiveFormFiller * pFormFiller,CPDFSDK_Widget * pWidget)31 CFFL_TextField::CFFL_TextField(CFFL_InteractiveFormFiller* pFormFiller,
32                                CPDFSDK_Widget* pWidget)
33     : CFFL_TextObject(pFormFiller, pWidget) {}
34 
~CFFL_TextField()35 CFFL_TextField::~CFFL_TextField() {
36   // See comment in cffl_formfiller.h.
37   // The font map should be stored somewhere more appropriate so it will live
38   // until the PWL_Edit is done with it. pdfium:566
39   DestroyWindows();
40 }
41 
GetCreateParam()42 CPWL_Wnd::CreateParams CFFL_TextField::GetCreateParam() {
43   CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
44   int nFlags = m_pWidget->GetFieldFlags();
45   if (nFlags & pdfium::form_flags::kTextPassword)
46     cp.dwFlags |= PES_PASSWORD;
47 
48   if (nFlags & pdfium::form_flags::kTextMultiline) {
49     cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP;
50     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll))
51       cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL;
52   } else {
53     cp.dwFlags |= PES_CENTER;
54     if (!(nFlags & pdfium::form_flags::kTextDoNotScroll))
55       cp.dwFlags |= PES_AUTOSCROLL;
56   }
57 
58   if (nFlags & pdfium::form_flags::kTextComb)
59     cp.dwFlags |= PES_CHARARRAY;
60 
61   if (nFlags & pdfium::form_flags::kTextRichText)
62     cp.dwFlags |= PES_RICH;
63 
64   cp.dwFlags |= PES_UNDO;
65 
66   switch (m_pWidget->GetAlignment()) {
67     default:
68     case kLeft:
69       cp.dwFlags |= PES_LEFT;
70       break;
71     case kCenter:
72       cp.dwFlags |= PES_MIDDLE;
73       break;
74     case kRight:
75       cp.dwFlags |= PES_RIGHT;
76       break;
77   }
78   cp.pFontMap = GetOrCreateFontMap();
79   return cp;
80 }
81 
NewPWLWindow(const CPWL_Wnd::CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)82 std::unique_ptr<CPWL_Wnd> CFFL_TextField::NewPWLWindow(
83     const CPWL_Wnd::CreateParams& cp,
84     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData) {
85   static_cast<CFFL_PerWindowData*>(pAttachedData.get())->SetFormField(this);
86   auto pWnd = std::make_unique<CPWL_Edit>(cp, std::move(pAttachedData));
87   pWnd->Realize();
88 
89   int32_t nMaxLen = m_pWidget->GetMaxLen();
90   WideString swValue = m_pWidget->GetValue();
91   if (nMaxLen > 0) {
92     if (pWnd->HasFlag(PES_CHARARRAY)) {
93       pWnd->SetCharArray(nMaxLen);
94       pWnd->SetAlignFormatVerticalCenter();
95     } else {
96       pWnd->SetLimitChar(nMaxLen);
97     }
98   }
99   pWnd->SetText(swValue);
100   return std::move(pWnd);
101 }
102 
OnChar(CPDFSDK_Widget * pWidget,uint32_t nChar,Mask<FWL_EVENTFLAG> nFlags)103 bool CFFL_TextField::OnChar(CPDFSDK_Widget* pWidget,
104                             uint32_t nChar,
105                             Mask<FWL_EVENTFLAG> nFlags) {
106   switch (nChar) {
107     case pdfium::ascii::kReturn: {
108       if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kTextMultiline)
109         break;
110 
111       CPDFSDK_PageView* pPageView = GetCurPageView();
112       DCHECK(pPageView);
113       m_bValid = !m_bValid;
114       m_pFormFiller->Invalidate(pWidget->GetPage(),
115                                 pWidget->GetRect().GetOuterRect());
116       if (m_bValid) {
117         if (CPWL_Wnd* pWnd = CreateOrUpdatePWLWindow(pPageView))
118           pWnd->SetFocus();
119         break;
120       }
121 
122       if (!CommitData(pPageView, nFlags))
123         return false;
124 
125       DestroyPWLWindow(pPageView);
126       return true;
127     }
128     case pdfium::ascii::kEscape: {
129       CPDFSDK_PageView* pPageView = GetCurPageView();
130       DCHECK(pPageView);
131       EscapeFiller(pPageView, true);
132       return true;
133     }
134   }
135 
136   return CFFL_TextObject::OnChar(pWidget, nChar, nFlags);
137 }
138 
IsDataChanged(const CPDFSDK_PageView * pPageView)139 bool CFFL_TextField::IsDataChanged(const CPDFSDK_PageView* pPageView) {
140   CPWL_Edit* pEdit = GetPWLEdit(pPageView);
141   return pEdit && pEdit->GetText() != m_pWidget->GetValue();
142 }
143 
SaveData(const CPDFSDK_PageView * pPageView)144 void CFFL_TextField::SaveData(const CPDFSDK_PageView* pPageView) {
145   ObservedPtr<CPWL_Edit> observed_edit(GetPWLEdit(pPageView));
146   if (!observed_edit) {
147     return;
148   }
149   WideString sOldValue = m_pWidget->GetValue();
150   if (!observed_edit) {
151     return;
152   }
153   WideString sNewValue = observed_edit->GetText();
154   ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget);
155   ObservedPtr<CFFL_TextField> observed_this(this);
156   m_pWidget->SetValue(sNewValue);
157   if (!observed_widget) {
158     return;
159   }
160   m_pWidget->ResetFieldAppearance();
161   if (!observed_widget) {
162     return;
163   }
164   m_pWidget->UpdateField();
165   if (!observed_widget || !observed_this) {
166     return;
167   }
168   SetChangeMark();
169 }
170 
GetActionData(const CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,CFFL_FieldAction & fa)171 void CFFL_TextField::GetActionData(const CPDFSDK_PageView* pPageView,
172                                    CPDF_AAction::AActionType type,
173                                    CFFL_FieldAction& fa) {
174   switch (type) {
175     case CPDF_AAction::kKeyStroke:
176       if (CPWL_Edit* pWnd = GetPWLEdit(pPageView)) {
177         fa.bFieldFull = pWnd->IsTextFull();
178         fa.sValue = pWnd->GetText();
179         if (fa.bFieldFull) {
180           fa.sChange.clear();
181           fa.sChangeEx.clear();
182         }
183       }
184       break;
185     case CPDF_AAction::kValidate:
186       if (CPWL_Edit* pWnd = GetPWLEdit(pPageView)) {
187         fa.sValue = pWnd->GetText();
188       }
189       break;
190     case CPDF_AAction::kLoseFocus:
191     case CPDF_AAction::kGetFocus:
192       fa.sValue = m_pWidget->GetValue();
193       break;
194     default:
195       break;
196   }
197 }
198 
SetActionData(const CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,const CFFL_FieldAction & fa)199 void CFFL_TextField::SetActionData(const CPDFSDK_PageView* pPageView,
200                                    CPDF_AAction::AActionType type,
201                                    const CFFL_FieldAction& fa) {
202   switch (type) {
203     case CPDF_AAction::kKeyStroke:
204       if (CPWL_Edit* pEdit = GetPWLEdit(pPageView)) {
205         pEdit->SetFocus();
206         pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
207         pEdit->ReplaceSelection(fa.sChange);
208       }
209       break;
210     default:
211       break;
212   }
213 }
214 
SavePWLWindowState(const CPDFSDK_PageView * pPageView)215 void CFFL_TextField::SavePWLWindowState(const CPDFSDK_PageView* pPageView) {
216   CPWL_Edit* pWnd = GetPWLEdit(pPageView);
217   if (!pWnd)
218     return;
219 
220   std::tie(m_State.nStart, m_State.nEnd) = pWnd->GetSelection();
221   m_State.sValue = pWnd->GetText();
222 }
223 
RecreatePWLWindowFromSavedState(const CPDFSDK_PageView * pPageView)224 void CFFL_TextField::RecreatePWLWindowFromSavedState(
225     const CPDFSDK_PageView* pPageView) {
226   CPWL_Edit* pWnd = CreateOrUpdatePWLEdit(pPageView);
227   if (!pWnd)
228     return;
229 
230   pWnd->SetText(m_State.sValue);
231   pWnd->SetSelection(m_State.nStart, m_State.nEnd);
232 }
233 
234 #ifdef PDF_ENABLE_XFA
IsFieldFull(const CPDFSDK_PageView * pPageView)235 bool CFFL_TextField::IsFieldFull(const CPDFSDK_PageView* pPageView) {
236   CPWL_Edit* pWnd = GetPWLEdit(pPageView);
237   return pWnd && pWnd->IsTextFull();
238 }
239 #endif  // PDF_ENABLE_XFA
240 
OnSetFocusForEdit(CPWL_Edit * pEdit)241 void CFFL_TextField::OnSetFocusForEdit(CPWL_Edit* pEdit) {
242   pEdit->SetCharSet(FX_Charset::kChineseSimplified);
243   pEdit->SetReadyToInput();
244   m_pFormFiller->OnSetFieldInputFocus(pEdit->GetText());
245 }
246 
GetPWLEdit(const CPDFSDK_PageView * pPageView) const247 CPWL_Edit* CFFL_TextField::GetPWLEdit(const CPDFSDK_PageView* pPageView) const {
248   return static_cast<CPWL_Edit*>(GetPWLWindow(pPageView));
249 }
250 
CreateOrUpdatePWLEdit(const CPDFSDK_PageView * pPageView)251 CPWL_Edit* CFFL_TextField::CreateOrUpdatePWLEdit(
252     const CPDFSDK_PageView* pPageView) {
253   return static_cast<CPWL_Edit*>(CreateOrUpdatePWLWindow(pPageView));
254 }
255