• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 "xfa/fxfa/cxfa_fftextedit.h"
8 
9 #include <utility>
10 
11 #include "xfa/fwl/cfwl_datetimepicker.h"
12 #include "xfa/fwl/cfwl_edit.h"
13 #include "xfa/fwl/cfwl_eventcheckword.h"
14 #include "xfa/fwl/cfwl_eventtarget.h"
15 #include "xfa/fwl/cfwl_eventtextchanged.h"
16 #include "xfa/fwl/cfwl_messagekillfocus.h"
17 #include "xfa/fwl/cfwl_messagesetfocus.h"
18 #include "xfa/fwl/cfwl_notedriver.h"
19 #include "xfa/fxfa/cxfa_eventparam.h"
20 #include "xfa/fxfa/cxfa_ffapp.h"
21 #include "xfa/fxfa/cxfa_ffdoc.h"
22 #include "xfa/fxfa/parser/cxfa_node.h"
23 #include "xfa/fxfa/parser/cxfa_para.h"
24 
25 namespace {
26 
ToEdit(CFWL_Widget * widget)27 CFWL_Edit* ToEdit(CFWL_Widget* widget) {
28   return static_cast<CFWL_Edit*>(widget);
29 }
30 
31 }  // namespace
32 
CXFA_FFTextEdit(CXFA_Node * pNode)33 CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_Node* pNode)
34     : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
35 
~CXFA_FFTextEdit()36 CXFA_FFTextEdit::~CXFA_FFTextEdit() {
37   if (m_pNormalWidget) {
38     CFWL_NoteDriver* pNoteDriver =
39         m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
40     pNoteDriver->UnregisterEventTarget(m_pNormalWidget.get());
41   }
42 }
43 
LoadWidget()44 bool CXFA_FFTextEdit::LoadWidget() {
45   auto pNewWidget = pdfium::MakeUnique<CFWL_Edit>(
46       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
47   CFWL_Edit* pFWLEdit = pNewWidget.get();
48   m_pNormalWidget = std::move(pNewWidget);
49   m_pNormalWidget->SetLayoutItem(this);
50 
51   CFWL_NoteDriver* pNoteDriver =
52       m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
53   pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
54                                    m_pNormalWidget.get());
55   m_pOldDelegate = m_pNormalWidget->GetDelegate();
56   m_pNormalWidget->SetDelegate(this);
57   m_pNormalWidget->LockUpdate();
58   UpdateWidgetProperty();
59 
60   pFWLEdit->SetText(
61       m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
62   m_pNormalWidget->UnlockUpdate();
63   return CXFA_FFField::LoadWidget();
64 }
65 
UpdateWidgetProperty()66 void CXFA_FFTextEdit::UpdateWidgetProperty() {
67   CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
68   if (!pWidget)
69     return;
70 
71   uint32_t dwStyle = 0;
72   uint32_t dwExtendedStyle =
73       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar;
74   dwExtendedStyle |= UpdateUIProperty();
75   if (m_pNode->GetWidgetAcc()->IsMultiLine()) {
76     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
77     if (!m_pNode->GetWidgetAcc()->IsVerticalScrollPolicyOff()) {
78       dwStyle |= FWL_WGTSTYLE_VScroll;
79       dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoVScroll;
80     }
81   } else if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff()) {
82     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
83   }
84   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
85     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
86     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine;
87   }
88 
89   XFA_Element eType;
90   int32_t iMaxChars;
91   std::tie(eType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
92   if (eType == XFA_Element::ExData)
93     iMaxChars = 0;
94 
95   Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
96   if (!numCells) {
97     pWidget->SetLimit(iMaxChars);
98   } else if (*numCells == 0) {
99     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
100     pWidget->SetLimit(iMaxChars > 0 ? iMaxChars : 1);
101   } else {
102     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
103     pWidget->SetLimit(*numCells);
104   }
105 
106   dwExtendedStyle |= GetAlignment();
107   m_pNormalWidget->ModifyStyles(dwStyle, 0xFFFFFFFF);
108   m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
109 }
110 
OnLButtonDown(uint32_t dwFlags,const CFX_PointF & point)111 bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
112   if (!PtInActiveRect(point))
113     return false;
114   if (!IsFocused()) {
115     m_dwStatus |= XFA_WidgetStatus_Focused;
116     UpdateFWLData();
117     AddInvalidateRect();
118   }
119 
120   SetButtonDown(true);
121   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
122   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
123   ms.m_dwFlags = dwFlags;
124   ms.m_pos = FWLToClient(point);
125   TranslateFWLMessage(&ms);
126   return true;
127 }
128 
OnRButtonDown(uint32_t dwFlags,const CFX_PointF & point)129 bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
130   if (!m_pNode->IsOpenAccess())
131     return false;
132   if (!PtInActiveRect(point))
133     return false;
134   if (!IsFocused()) {
135     m_dwStatus |= XFA_WidgetStatus_Focused;
136     UpdateFWLData();
137     AddInvalidateRect();
138   }
139 
140   SetButtonDown(true);
141   CFWL_MessageMouse ms(nullptr, nullptr);
142   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
143   ms.m_dwFlags = dwFlags;
144   ms.m_pos = FWLToClient(point);
145   TranslateFWLMessage(&ms);
146   return true;
147 }
148 
OnRButtonUp(uint32_t dwFlags,const CFX_PointF & point)149 bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
150   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
151     return false;
152 
153   GetDoc()->GetDocEnvironment()->PopupMenu(this, point);
154   return true;
155 }
156 
OnSetFocus(CXFA_FFWidget * pOldWidget)157 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
158   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
159   if (!IsFocused()) {
160     m_dwStatus |= XFA_WidgetStatus_Focused;
161     UpdateFWLData();
162     AddInvalidateRect();
163   }
164   CXFA_FFWidget::OnSetFocus(pOldWidget);
165   CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget.get());
166   TranslateFWLMessage(&ms);
167   return true;
168 }
169 
OnKillFocus(CXFA_FFWidget * pNewWidget)170 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
171   CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget.get());
172   TranslateFWLMessage(&ms);
173   m_dwStatus &= ~XFA_WidgetStatus_Focused;
174 
175   SetEditScrollOffset();
176   ProcessCommittedData();
177   UpdateFWLData();
178   AddInvalidateRect();
179   CXFA_FFWidget::OnKillFocus(pNewWidget);
180 
181   m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
182   return true;
183 }
184 
CommitData()185 bool CXFA_FFTextEdit::CommitData() {
186   WideString wsText = static_cast<CFWL_Edit*>(m_pNormalWidget.get())->GetText();
187   if (m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Edit, wsText)) {
188     m_pNode->GetWidgetAcc()->UpdateUIDisplay(GetDoc()->GetDocView(), this);
189     return true;
190   }
191   ValidateNumberField(wsText);
192   return false;
193 }
194 
ValidateNumberField(const WideString & wsText)195 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
196   CXFA_WidgetAcc* pAcc = GetNode()->GetWidgetAcc();
197   if (!pAcc || pAcc->GetUIType() != XFA_Element::NumericEdit)
198     return;
199 
200   IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
201   if (!pAppProvider)
202     return;
203 
204   WideString wsSomField = pAcc->GetNode()->GetSOMExpression();
205   pAppProvider->MsgBox(WideString::Format(L"%ls can not contain %ls",
206                                           wsText.c_str(), wsSomField.c_str()),
207                        pAppProvider->GetAppTitle(), XFA_MBICON_Error,
208                        XFA_MB_OK);
209 }
210 
IsDataChanged()211 bool CXFA_FFTextEdit::IsDataChanged() {
212   return (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged) != 0;
213 }
214 
GetAlignment()215 uint32_t CXFA_FFTextEdit::GetAlignment() {
216   CXFA_Para* para = m_pNode->GetParaIfExists();
217   if (!para)
218     return 0;
219 
220   uint32_t dwExtendedStyle = 0;
221   switch (para->GetHorizontalAlign()) {
222     case XFA_AttributeEnum::Center:
223       dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
224       break;
225     case XFA_AttributeEnum::Justify:
226       dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
227       break;
228     case XFA_AttributeEnum::JustifyAll:
229     case XFA_AttributeEnum::Radix:
230       break;
231     case XFA_AttributeEnum::Right:
232       dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
233       break;
234     default:
235       dwExtendedStyle |= FWL_STYLEEXT_EDT_HNear;
236       break;
237   }
238 
239   switch (para->GetVerticalAlign()) {
240     case XFA_AttributeEnum::Middle:
241       dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
242       break;
243     case XFA_AttributeEnum::Bottom:
244       dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
245       break;
246     default:
247       dwExtendedStyle |= FWL_STYLEEXT_EDT_VNear;
248       break;
249   }
250   return dwExtendedStyle;
251 }
252 
UpdateFWLData()253 bool CXFA_FFTextEdit::UpdateFWLData() {
254   if (!m_pNormalWidget)
255     return false;
256 
257   CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
258   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
259   if (IsFocused())
260     eType = XFA_VALUEPICTURE_Edit;
261 
262   bool bUpdate = false;
263   if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::TextEdit &&
264       !m_pNode->GetWidgetAcc()->GetNumberOfCells()) {
265     XFA_Element elementType;
266     int32_t iMaxChars;
267     std::tie(elementType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
268     if (elementType == XFA_Element::ExData)
269       iMaxChars = eType == XFA_VALUEPICTURE_Edit ? iMaxChars : 0;
270     if (pEdit->GetLimit() != iMaxChars) {
271       pEdit->SetLimit(iMaxChars);
272       bUpdate = true;
273     }
274   } else if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::Barcode) {
275     int32_t nDataLen = 0;
276     if (eType == XFA_VALUEPICTURE_Edit)
277       nDataLen = m_pNode->GetBarcodeAttribute_DataLength().value_or(0);
278 
279     pEdit->SetLimit(nDataLen);
280     bUpdate = true;
281   }
282 
283   WideString wsText = m_pNode->GetWidgetAcc()->GetValue(eType);
284   WideString wsOldText = pEdit->GetText();
285   if (wsText != wsOldText || (eType == XFA_VALUEPICTURE_Edit && bUpdate)) {
286     pEdit->SetText(wsText);
287     bUpdate = true;
288   }
289   if (bUpdate)
290     m_pNormalWidget->Update();
291 
292   return true;
293 }
294 
OnTextChanged(CFWL_Widget * pWidget,const WideString & wsChanged,const WideString & wsPrevText)295 void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
296                                     const WideString& wsChanged,
297                                     const WideString& wsPrevText) {
298   m_dwStatus |= XFA_WidgetStatus_TextEditValueChanged;
299   CXFA_EventParam eParam;
300   eParam.m_eType = XFA_EVENT_Change;
301   eParam.m_wsChange = wsChanged;
302   eParam.m_pTarget = m_pNode->GetWidgetAcc();
303   eParam.m_wsPrevText = wsPrevText;
304   CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
305   if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::DateTimeEdit) {
306     CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
307     eParam.m_wsNewText = pDateTime->GetEditText();
308     if (pDateTime->HasSelection()) {
309       size_t count;
310       std::tie(eParam.m_iSelStart, count) = pDateTime->GetSelection();
311       eParam.m_iSelEnd = eParam.m_iSelStart + count;
312     }
313   } else {
314     eParam.m_wsNewText = pEdit->GetText();
315     if (pEdit->HasSelection())
316       std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) = pEdit->GetSelection();
317   }
318   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
319 }
320 
OnTextFull(CFWL_Widget * pWidget)321 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
322   CXFA_EventParam eParam;
323   eParam.m_eType = XFA_EVENT_Full;
324   eParam.m_pTarget = m_pNode->GetWidgetAcc();
325   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Full, &eParam);
326 }
327 
CheckWord(const ByteStringView & sWord)328 bool CXFA_FFTextEdit::CheckWord(const ByteStringView& sWord) {
329   return sWord.IsEmpty() ||
330          m_pNode->GetWidgetAcc()->GetUIType() != XFA_Element::TextEdit;
331 }
332 
OnProcessMessage(CFWL_Message * pMessage)333 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
334   m_pOldDelegate->OnProcessMessage(pMessage);
335 }
336 
OnProcessEvent(CFWL_Event * pEvent)337 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
338   CXFA_FFField::OnProcessEvent(pEvent);
339   switch (pEvent->GetType()) {
340     case CFWL_Event::Type::TextChanged: {
341       CFWL_EventTextChanged* event =
342           static_cast<CFWL_EventTextChanged*>(pEvent);
343       WideString wsChange;
344       OnTextChanged(m_pNormalWidget.get(), wsChange, event->wsPrevText);
345       break;
346     }
347     case CFWL_Event::Type::TextFull: {
348       OnTextFull(m_pNormalWidget.get());
349       break;
350     }
351     case CFWL_Event::Type::CheckWord: {
352       WideString wstr(L"FWL_EVENT_DTP_SelectChanged");
353       CFWL_EventCheckWord* event = static_cast<CFWL_EventCheckWord*>(pEvent);
354       event->bCheckWord = CheckWord(event->bsWord.AsStringView());
355       break;
356     }
357     default:
358       break;
359   }
360   m_pOldDelegate->OnProcessEvent(pEvent);
361 }
362 
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)363 void CXFA_FFTextEdit::OnDrawWidget(CXFA_Graphics* pGraphics,
364                                    const CFX_Matrix& matrix) {
365   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
366 }
367 
CanUndo()368 bool CXFA_FFTextEdit::CanUndo() {
369   return ToEdit(m_pNormalWidget.get())->CanUndo();
370 }
371 
CanRedo()372 bool CXFA_FFTextEdit::CanRedo() {
373   return ToEdit(m_pNormalWidget.get())->CanRedo();
374 }
375 
Undo()376 bool CXFA_FFTextEdit::Undo() {
377   return ToEdit(m_pNormalWidget.get())->Undo();
378 }
379 
Redo()380 bool CXFA_FFTextEdit::Redo() {
381   return ToEdit(m_pNormalWidget.get())->Redo();
382 }
383 
CanCopy()384 bool CXFA_FFTextEdit::CanCopy() {
385   return ToEdit(m_pNormalWidget.get())->HasSelection();
386 }
387 
CanCut()388 bool CXFA_FFTextEdit::CanCut() {
389   if (ToEdit(m_pNormalWidget.get())->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
390     return false;
391   return ToEdit(m_pNormalWidget.get())->HasSelection();
392 }
393 
CanPaste()394 bool CXFA_FFTextEdit::CanPaste() {
395   return !(ToEdit(m_pNormalWidget.get())->GetStylesEx() &
396            FWL_STYLEEXT_EDT_ReadOnly);
397 }
398 
CanSelectAll()399 bool CXFA_FFTextEdit::CanSelectAll() {
400   return ToEdit(m_pNormalWidget.get())->GetTextLength() > 0;
401 }
402 
Copy()403 Optional<WideString> CXFA_FFTextEdit::Copy() {
404   return ToEdit(m_pNormalWidget.get())->Copy();
405 }
406 
Cut()407 Optional<WideString> CXFA_FFTextEdit::Cut() {
408   return ToEdit(m_pNormalWidget.get())->Cut();
409 }
410 
Paste(const WideString & wsPaste)411 bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
412   return ToEdit(m_pNormalWidget.get())->Paste(wsPaste);
413 }
414 
SelectAll()415 void CXFA_FFTextEdit::SelectAll() {
416   ToEdit(m_pNormalWidget.get())->SelectAll();
417 }
418 
Delete()419 void CXFA_FFTextEdit::Delete() {
420   ToEdit(m_pNormalWidget.get())->ClearText();
421 }
422 
DeSelect()423 void CXFA_FFTextEdit::DeSelect() {
424   ToEdit(m_pNormalWidget.get())->ClearSelection();
425 }
426 
GetFormFieldType()427 FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
428   return FormFieldType::kXFA_TextField;
429 }
430