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 "fpdfsdk/cpdfsdk_formfillenvironment.h"
10 #include "fpdfsdk/cpdfsdk_widget.h"
11 #include "fpdfsdk/formfiller/cba_fontmap.h"
12 #include "fpdfsdk/fsdk_common.h"
13 #include "third_party/base/ptr_util.h"
14
CFFL_TextField(CPDFSDK_FormFillEnvironment * pApp,CPDFSDK_Widget * pWidget)15 CFFL_TextField::CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp,
16 CPDFSDK_Widget* pWidget)
17 : CFFL_TextObject(pApp, pWidget) {}
18
~CFFL_TextField()19 CFFL_TextField::~CFFL_TextField() {
20 for (const auto& it : m_Maps)
21 it.second->InvalidateFocusHandler(this);
22
23 // See comment in cffl_formfiller.h.
24 // The font map should be stored somewhere more appropriate so it will live
25 // until the PWL_Edit is done with it. pdfium:566
26 DestroyWindows();
27 }
28
GetCreateParam()29 CPWL_Wnd::CreateParams CFFL_TextField::GetCreateParam() {
30 CPWL_Wnd::CreateParams cp = CFFL_TextObject::GetCreateParam();
31 int nFlags = m_pWidget->GetFieldFlags();
32 if (nFlags & FIELDFLAG_PASSWORD)
33 cp.dwFlags |= PES_PASSWORD;
34
35 if (nFlags & FIELDFLAG_MULTILINE) {
36 cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP;
37 if (!(nFlags & FIELDFLAG_DONOTSCROLL))
38 cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL;
39 } else {
40 cp.dwFlags |= PES_CENTER;
41 if (!(nFlags & FIELDFLAG_DONOTSCROLL))
42 cp.dwFlags |= PES_AUTOSCROLL;
43 }
44
45 if (nFlags & FIELDFLAG_COMB)
46 cp.dwFlags |= PES_CHARARRAY;
47
48 if (nFlags & FIELDFLAG_RICHTEXT)
49 cp.dwFlags |= PES_RICH;
50
51 cp.dwFlags |= PES_UNDO;
52
53 switch (m_pWidget->GetAlignment()) {
54 default:
55 case BF_ALIGN_LEFT:
56 cp.dwFlags |= PES_LEFT;
57 break;
58 case BF_ALIGN_MIDDLE:
59 cp.dwFlags |= PES_MIDDLE;
60 break;
61 case BF_ALIGN_RIGHT:
62 cp.dwFlags |= PES_RIGHT;
63 break;
64 }
65 cp.pFontMap = MaybeCreateFontMap();
66 cp.pFocusHandler = this;
67 return cp;
68 }
69
NewPDFWindow(const CPWL_Wnd::CreateParams & cp)70 CPWL_Wnd* CFFL_TextField::NewPDFWindow(const CPWL_Wnd::CreateParams& cp) {
71 auto* pWnd = new CPWL_Edit();
72 pWnd->AttachFFLData(this);
73 pWnd->Create(cp);
74 pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
75
76 int32_t nMaxLen = m_pWidget->GetMaxLen();
77 WideString swValue = m_pWidget->GetValue();
78
79 if (nMaxLen > 0) {
80 if (pWnd->HasFlag(PES_CHARARRAY)) {
81 pWnd->SetCharArray(nMaxLen);
82 pWnd->SetAlignFormatV(PEAV_CENTER);
83 } else {
84 pWnd->SetLimitChar(nMaxLen);
85 }
86 }
87
88 pWnd->SetText(swValue);
89 return pWnd;
90 }
91
OnChar(CPDFSDK_Annot * pAnnot,uint32_t nChar,uint32_t nFlags)92 bool CFFL_TextField::OnChar(CPDFSDK_Annot* pAnnot,
93 uint32_t nChar,
94 uint32_t nFlags) {
95 switch (nChar) {
96 case FWL_VKEY_Return: {
97 if (m_pWidget->GetFieldFlags() & FIELDFLAG_MULTILINE)
98 break;
99
100 CPDFSDK_PageView* pPageView = GetCurPageView(true);
101 ASSERT(pPageView);
102 m_bValid = !m_bValid;
103 m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
104 pAnnot->GetRect().GetOuterRect());
105
106 if (m_bValid) {
107 if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
108 pWnd->SetFocus();
109 break;
110 }
111
112 if (!CommitData(pPageView, nFlags))
113 return false;
114
115 DestroyPDFWindow(pPageView);
116 return true;
117 }
118 case FWL_VKEY_Escape: {
119 CPDFSDK_PageView* pPageView = GetCurPageView(true);
120 ASSERT(pPageView);
121 EscapeFiller(pPageView, true);
122 return true;
123 }
124 }
125
126 return CFFL_TextObject::OnChar(pAnnot, nChar, nFlags);
127 }
128
IsDataChanged(CPDFSDK_PageView * pPageView)129 bool CFFL_TextField::IsDataChanged(CPDFSDK_PageView* pPageView) {
130 CPWL_Edit* pEdit = GetEdit(pPageView, false);
131 return pEdit && pEdit->GetText() != m_pWidget->GetValue();
132 }
133
SaveData(CPDFSDK_PageView * pPageView)134 void CFFL_TextField::SaveData(CPDFSDK_PageView* pPageView) {
135 CPWL_Edit* pWnd = GetEdit(pPageView, false);
136 if (!pWnd)
137 return;
138
139 WideString sOldValue = m_pWidget->GetValue();
140 WideString sNewValue = pWnd->GetText();
141
142 CPDFSDK_Widget::ObservedPtr observed_widget(m_pWidget.Get());
143 CFFL_TextField::ObservedPtr observed_this(this);
144
145 m_pWidget->SetValue(sNewValue, false);
146 if (!observed_widget)
147 return;
148 m_pWidget->ResetFieldAppearance(true);
149 if (!observed_widget)
150 return;
151 m_pWidget->UpdateField();
152 if (!observed_widget || !observed_this)
153 return;
154 SetChangeMark();
155 }
156
GetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,PDFSDK_FieldAction & fa)157 void CFFL_TextField::GetActionData(CPDFSDK_PageView* pPageView,
158 CPDF_AAction::AActionType type,
159 PDFSDK_FieldAction& fa) {
160 switch (type) {
161 case CPDF_AAction::KeyStroke:
162 if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
163 fa.bFieldFull = pWnd->IsTextFull();
164
165 fa.sValue = pWnd->GetText();
166
167 if (fa.bFieldFull) {
168 fa.sChange = L"";
169 fa.sChangeEx = L"";
170 }
171 }
172 break;
173 case CPDF_AAction::Validate:
174 if (CPWL_Edit* pWnd = GetEdit(pPageView, false)) {
175 fa.sValue = pWnd->GetText();
176 }
177 break;
178 case CPDF_AAction::LoseFocus:
179 case CPDF_AAction::GetFocus:
180 fa.sValue = m_pWidget->GetValue();
181 break;
182 default:
183 break;
184 }
185 }
186
SetActionData(CPDFSDK_PageView * pPageView,CPDF_AAction::AActionType type,const PDFSDK_FieldAction & fa)187 void CFFL_TextField::SetActionData(CPDFSDK_PageView* pPageView,
188 CPDF_AAction::AActionType type,
189 const PDFSDK_FieldAction& fa) {
190 switch (type) {
191 case CPDF_AAction::KeyStroke:
192 if (CPWL_Edit* pEdit = GetEdit(pPageView, false)) {
193 pEdit->SetFocus();
194 pEdit->SetSelection(fa.nSelStart, fa.nSelEnd);
195 pEdit->ReplaceSel(fa.sChange);
196 }
197 break;
198 default:
199 break;
200 }
201 }
202
IsActionDataChanged(CPDF_AAction::AActionType type,const PDFSDK_FieldAction & faOld,const PDFSDK_FieldAction & faNew)203 bool CFFL_TextField::IsActionDataChanged(CPDF_AAction::AActionType type,
204 const PDFSDK_FieldAction& faOld,
205 const PDFSDK_FieldAction& faNew) {
206 switch (type) {
207 case CPDF_AAction::KeyStroke:
208 return (!faOld.bFieldFull && faOld.nSelEnd != faNew.nSelEnd) ||
209 faOld.nSelStart != faNew.nSelStart ||
210 faOld.sChange != faNew.sChange;
211 default:
212 break;
213 }
214
215 return false;
216 }
217
SaveState(CPDFSDK_PageView * pPageView)218 void CFFL_TextField::SaveState(CPDFSDK_PageView* pPageView) {
219 ASSERT(pPageView);
220
221 CPWL_Edit* pWnd = GetEdit(pPageView, false);
222 if (!pWnd)
223 return;
224
225 pWnd->GetSelection(m_State.nStart, m_State.nEnd);
226 m_State.sValue = pWnd->GetText();
227 }
228
RestoreState(CPDFSDK_PageView * pPageView)229 void CFFL_TextField::RestoreState(CPDFSDK_PageView* pPageView) {
230 ASSERT(pPageView);
231
232 CPWL_Edit* pWnd = GetEdit(pPageView, true);
233 if (!pWnd)
234 return;
235
236 pWnd->SetText(m_State.sValue);
237 pWnd->SetSelection(m_State.nStart, m_State.nEnd);
238 }
239
240 #ifdef PDF_ENABLE_XFA
IsFieldFull(CPDFSDK_PageView * pPageView)241 bool CFFL_TextField::IsFieldFull(CPDFSDK_PageView* pPageView) {
242 CPWL_Edit* pWnd = GetEdit(pPageView, false);
243 return pWnd && pWnd->IsTextFull();
244 }
245 #endif // PDF_ENABLE_XFA
246
OnSetFocus(CPWL_Edit * pEdit)247 void CFFL_TextField::OnSetFocus(CPWL_Edit* pEdit) {
248 pEdit->SetCharSet(FX_CHARSET_ChineseSimplified);
249 pEdit->SetReadyToInput();
250
251 WideString wsText = pEdit->GetText();
252 int nCharacters = wsText.GetLength();
253 ByteString bsUTFText = wsText.UTF16LE_Encode();
254 auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
255 m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
256 }
257
GetEdit(CPDFSDK_PageView * pPageView,bool bNew)258 CPWL_Edit* CFFL_TextField::GetEdit(CPDFSDK_PageView* pPageView, bool bNew) {
259 return static_cast<CPWL_Edit*>(GetPDFWindow(pPageView, bNew));
260 }
261