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
15CFFL_TextField::CFFL_TextField(CPDFSDK_FormFillEnvironment* pApp,
16                               CPDFSDK_Annot* pAnnot)
17    : CFFL_FormFiller(pApp, pAnnot) {}
18
19CFFL_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
29PWL_CREATEPARAM CFFL_TextField::GetCreateParam() {
30  PWL_CREATEPARAM cp = CFFL_FormFiller::GetCreateParam();
31
32  int nFlags = m_pWidget->GetFieldFlags();
33
34  if (nFlags & FIELDFLAG_PASSWORD) {
35    cp.dwFlags |= PES_PASSWORD;
36  }
37
38  if (nFlags & FIELDFLAG_MULTILINE) {
39    cp.dwFlags |= PES_MULTILINE | PES_AUTORETURN | PES_TOP;
40
41    if (!(nFlags & FIELDFLAG_DONOTSCROLL)) {
42      cp.dwFlags |= PWS_VSCROLL | PES_AUTOSCROLL;
43    }
44  } else {
45    cp.dwFlags |= PES_CENTER;
46
47    if (!(nFlags & FIELDFLAG_DONOTSCROLL)) {
48      cp.dwFlags |= PES_AUTOSCROLL;
49    }
50  }
51
52  if (nFlags & FIELDFLAG_COMB) {
53    cp.dwFlags |= PES_CHARARRAY;
54  }
55
56  if (nFlags & FIELDFLAG_RICHTEXT) {
57    cp.dwFlags |= PES_RICH;
58  }
59
60  cp.dwFlags |= PES_UNDO;
61
62  switch (m_pWidget->GetAlignment()) {
63    default:
64    case BF_ALIGN_LEFT:
65      cp.dwFlags |= PES_LEFT;
66      break;
67    case BF_ALIGN_MIDDLE:
68      cp.dwFlags |= PES_MIDDLE;
69      break;
70    case BF_ALIGN_RIGHT:
71      cp.dwFlags |= PES_RIGHT;
72      break;
73  }
74
75  if (!m_pFontMap) {
76    m_pFontMap = pdfium::MakeUnique<CBA_FontMap>(
77        m_pWidget, m_pFormFillEnv->GetSysHandler());
78  }
79  cp.pFontMap = m_pFontMap.get();
80  cp.pFocusHandler = this;
81
82  return cp;
83}
84
85CPWL_Wnd* CFFL_TextField::NewPDFWindow(const PWL_CREATEPARAM& cp,
86                                       CPDFSDK_PageView* pPageView) {
87  CPWL_Edit* pWnd = new CPWL_Edit();
88  pWnd->AttachFFLData(this);
89  pWnd->Create(cp);
90  pWnd->SetFillerNotify(m_pFormFillEnv->GetInteractiveFormFiller());
91
92  int32_t nMaxLen = m_pWidget->GetMaxLen();
93  CFX_WideString swValue = m_pWidget->GetValue();
94
95  if (nMaxLen > 0) {
96    if (pWnd->HasFlag(PES_CHARARRAY)) {
97      pWnd->SetCharArray(nMaxLen);
98      pWnd->SetAlignFormatV(PEAV_CENTER);
99    } else {
100      pWnd->SetLimitChar(nMaxLen);
101    }
102  }
103
104  pWnd->SetText(swValue);
105  return pWnd;
106}
107
108bool CFFL_TextField::OnChar(CPDFSDK_Annot* pAnnot,
109                            uint32_t nChar,
110                            uint32_t nFlags) {
111  switch (nChar) {
112    case FWL_VKEY_Return:
113      if (!(m_pWidget->GetFieldFlags() & FIELDFLAG_MULTILINE)) {
114        CPDFSDK_PageView* pPageView = GetCurPageView(true);
115        ASSERT(pPageView);
116        m_bValid = !m_bValid;
117        m_pFormFillEnv->Invalidate(pAnnot->GetUnderlyingPage(),
118                                   pAnnot->GetRect().ToFxRect());
119
120        if (m_bValid) {
121          if (CPWL_Wnd* pWnd = GetPDFWindow(pPageView, true))
122            pWnd->SetFocus();
123        } else {
124          if (CommitData(pPageView, nFlags)) {
125            DestroyPDFWindow(pPageView);
126            return true;
127          }
128          return false;
129        }
130      }
131      break;
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_FormFiller::OnChar(pAnnot, nChar, nFlags);
141}
142
143bool CFFL_TextField::IsDataChanged(CPDFSDK_PageView* pPageView) {
144  if (CPWL_Edit* pEdit = (CPWL_Edit*)GetPDFWindow(pPageView, false))
145    return pEdit->GetText() != m_pWidget->GetValue();
146
147  return false;
148}
149
150void CFFL_TextField::SaveData(CPDFSDK_PageView* pPageView) {
151  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
152    CFX_WideString sOldValue = m_pWidget->GetValue();
153    CFX_WideString sNewValue = pWnd->GetText();
154
155    m_pWidget->SetValue(sNewValue, false);
156    m_pWidget->ResetFieldAppearance(true);
157    m_pWidget->UpdateField();
158    SetChangeMark();
159  }
160}
161
162void CFFL_TextField::GetActionData(CPDFSDK_PageView* pPageView,
163                                   CPDF_AAction::AActionType type,
164                                   PDFSDK_FieldAction& fa) {
165  switch (type) {
166    case CPDF_AAction::KeyStroke:
167      if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
168        fa.bFieldFull = pWnd->IsTextFull();
169
170        fa.sValue = pWnd->GetText();
171
172        if (fa.bFieldFull) {
173          fa.sChange = L"";
174          fa.sChangeEx = L"";
175        }
176      }
177      break;
178    case CPDF_AAction::Validate:
179      if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
180        fa.sValue = pWnd->GetText();
181      }
182      break;
183    case CPDF_AAction::LoseFocus:
184    case CPDF_AAction::GetFocus:
185      fa.sValue = m_pWidget->GetValue();
186      break;
187    default:
188      break;
189  }
190}
191
192void CFFL_TextField::SetActionData(CPDFSDK_PageView* pPageView,
193                                   CPDF_AAction::AActionType type,
194                                   const PDFSDK_FieldAction& fa) {
195  switch (type) {
196    case CPDF_AAction::KeyStroke:
197      if (CPWL_Edit* pEdit = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
198        pEdit->SetFocus();
199        pEdit->SetSel(fa.nSelStart, fa.nSelEnd);
200        pEdit->ReplaceSel(fa.sChange);
201      }
202      break;
203    default:
204      break;
205  }
206}
207
208bool CFFL_TextField::IsActionDataChanged(CPDF_AAction::AActionType type,
209                                         const PDFSDK_FieldAction& faOld,
210                                         const PDFSDK_FieldAction& faNew) {
211  switch (type) {
212    case CPDF_AAction::KeyStroke:
213      return (!faOld.bFieldFull && faOld.nSelEnd != faNew.nSelEnd) ||
214             faOld.nSelStart != faNew.nSelStart ||
215             faOld.sChange != faNew.sChange;
216    default:
217      break;
218  }
219
220  return false;
221}
222
223void CFFL_TextField::SaveState(CPDFSDK_PageView* pPageView) {
224  ASSERT(pPageView);
225
226  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
227    pWnd->GetSel(m_State.nStart, m_State.nEnd);
228    m_State.sValue = pWnd->GetText();
229  }
230}
231
232void CFFL_TextField::RestoreState(CPDFSDK_PageView* pPageView) {
233  ASSERT(pPageView);
234
235  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, true)) {
236    pWnd->SetText(m_State.sValue);
237    pWnd->SetSel(m_State.nStart, m_State.nEnd);
238  }
239}
240
241CPWL_Wnd* CFFL_TextField::ResetPDFWindow(CPDFSDK_PageView* pPageView,
242                                         bool bRestoreValue) {
243  if (bRestoreValue)
244    SaveState(pPageView);
245
246  DestroyPDFWindow(pPageView);
247
248  CPWL_Wnd* pRet = nullptr;
249
250  if (bRestoreValue) {
251    RestoreState(pPageView);
252    pRet = GetPDFWindow(pPageView, false);
253  } else {
254    pRet = GetPDFWindow(pPageView, true);
255  }
256
257  m_pWidget->UpdateField();
258
259  return pRet;
260}
261
262#ifdef PDF_ENABLE_XFA
263bool CFFL_TextField::IsFieldFull(CPDFSDK_PageView* pPageView) {
264  if (CPWL_Edit* pWnd = (CPWL_Edit*)GetPDFWindow(pPageView, false)) {
265    return pWnd->IsTextFull();
266  }
267
268  return false;
269}
270#endif  // PDF_ENABLE_XFA
271
272void CFFL_TextField::OnSetFocus(CPWL_Wnd* pWnd) {
273  ASSERT(m_pFormFillEnv);
274  if (pWnd->GetClassName() == PWL_CLASSNAME_EDIT) {
275    CPWL_Edit* pEdit = (CPWL_Edit*)pWnd;
276    pEdit->SetCharSet(FXFONT_GB2312_CHARSET);
277    pEdit->SetCodePage(936);
278
279    pEdit->SetReadyToInput();
280    CFX_WideString wsText = pEdit->GetText();
281    int nCharacters = wsText.GetLength();
282    CFX_ByteString bsUTFText = wsText.UTF16LE_Encode();
283    unsigned short* pBuffer = (unsigned short*)bsUTFText.c_str();
284    m_pFormFillEnv->OnSetFieldInputFocus(pBuffer, nCharacters, true);
285  }
286}
287