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