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