• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 "xfa/fxfa/cxfa_fftextedit.h"
8 
9 #include <utility>
10 
11 #include "core/fxcrt/check.h"
12 #include "xfa/fwl/cfwl_datetimepicker.h"
13 #include "xfa/fwl/cfwl_edit.h"
14 #include "xfa/fwl/cfwl_eventtextwillchange.h"
15 #include "xfa/fwl/cfwl_messagekillfocus.h"
16 #include "xfa/fwl/cfwl_messagesetfocus.h"
17 #include "xfa/fwl/cfwl_notedriver.h"
18 #include "xfa/fxfa/cxfa_eventparam.h"
19 #include "xfa/fxfa/cxfa_ffapp.h"
20 #include "xfa/fxfa/cxfa_ffdoc.h"
21 #include "xfa/fxfa/cxfa_ffdocview.h"
22 #include "xfa/fxfa/parser/cxfa_barcode.h"
23 #include "xfa/fxfa/parser/cxfa_node.h"
24 #include "xfa/fxfa/parser/cxfa_para.h"
25 
26 namespace {
27 
ToEdit(CFWL_Widget * widget)28 CFWL_Edit* ToEdit(CFWL_Widget* widget) {
29   return static_cast<CFWL_Edit*>(widget);
30 }
31 
32 }  // namespace
33 
CXFA_FFTextEdit(CXFA_Node * pNode)34 CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_Node* pNode) : CXFA_FFField(pNode) {}
35 
36 CXFA_FFTextEdit::~CXFA_FFTextEdit() = default;
37 
PreFinalize()38 void CXFA_FFTextEdit::PreFinalize() {
39   if (GetNormalWidget()) {
40     CFWL_NoteDriver* pNoteDriver =
41         GetNormalWidget()->GetFWLApp()->GetNoteDriver();
42     pNoteDriver->UnregisterEventTarget(GetNormalWidget());
43   }
44 }
45 
Trace(cppgc::Visitor * visitor) const46 void CXFA_FFTextEdit::Trace(cppgc::Visitor* visitor) const {
47   CXFA_FFField::Trace(visitor);
48   visitor->Trace(m_pOldDelegate);
49 }
50 
LoadWidget()51 bool CXFA_FFTextEdit::LoadWidget() {
52   DCHECK(!IsLoaded());
53 
54   CFWL_Edit* pFWLEdit = cppgc::MakeGarbageCollected<CFWL_Edit>(
55       GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp(),
56       CFWL_Widget::Properties(), nullptr);
57   SetNormalWidget(pFWLEdit);
58   pFWLEdit->SetAdapterIface(this);
59 
60   CFWL_NoteDriver* pNoteDriver = pFWLEdit->GetFWLApp()->GetNoteDriver();
61   pNoteDriver->RegisterEventTarget(pFWLEdit, pFWLEdit);
62   m_pOldDelegate = pFWLEdit->GetDelegate();
63   pFWLEdit->SetDelegate(this);
64 
65   {
66     CFWL_Widget::ScopedUpdateLock update_lock(pFWLEdit);
67     UpdateWidgetProperty();
68     pFWLEdit->SetText(m_pNode->GetValue(XFA_ValuePicture::kDisplay));
69   }
70 
71   return CXFA_FFField::LoadWidget();
72 }
73 
UpdateWidgetProperty()74 void CXFA_FFTextEdit::UpdateWidgetProperty() {
75   CFWL_Edit* pWidget = ToEdit(GetNormalWidget());
76   if (!pWidget)
77     return;
78 
79   uint32_t dwStyle = 0;
80   uint32_t dwExtendedStyle =
81       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar;
82   dwExtendedStyle |= UpdateUIProperty();
83   if (m_pNode->IsMultiLine()) {
84     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
85     if (!m_pNode->IsVerticalScrollPolicyOff()) {
86       dwStyle |= FWL_STYLE_WGT_VScroll;
87       dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoVScroll;
88     }
89   } else if (!m_pNode->IsHorizontalScrollPolicyOff()) {
90     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
91   }
92   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
93     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
94     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine;
95   }
96 
97   auto [eType, iMaxChars] = m_pNode->GetMaxChars();
98   if (eType == XFA_Element::ExData)
99     iMaxChars = 0;
100 
101   std::optional<int32_t> numCells = m_pNode->GetNumberOfCells();
102   if (!numCells.has_value()) {
103     pWidget->SetLimit(iMaxChars);
104   } else if (numCells == 0) {
105     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
106     pWidget->SetLimit(iMaxChars > 0 ? iMaxChars : 1);
107   } else {
108     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
109     pWidget->SetLimit(numCells.value());
110   }
111 
112   dwExtendedStyle |= GetAlignment();
113   GetNormalWidget()->ModifyStyles(dwStyle, 0xFFFFFFFF);
114   GetNormalWidget()->ModifyStyleExts(dwExtendedStyle, 0xFFFFFFFF);
115 }
116 
AcceptsFocusOnButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point,CFWL_MessageMouse::MouseCommand command)117 bool CXFA_FFTextEdit::AcceptsFocusOnButtonDown(
118     Mask<XFA_FWL_KeyFlag> dwFlags,
119     const CFX_PointF& point,
120     CFWL_MessageMouse::MouseCommand command) {
121   if (command == CFWL_MessageMouse::MouseCommand::kRightButtonDown &&
122       !m_pNode->IsOpenAccess()) {
123     return false;
124   }
125   if (!PtInActiveRect(point))
126     return false;
127 
128   return true;
129 }
130 
OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)131 bool CXFA_FFTextEdit::OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,
132                                     const CFX_PointF& point) {
133   if (!IsFocused()) {
134     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
135     UpdateFWLData();
136     InvalidateRect();
137   }
138   SetButtonDown(true);
139   CFWL_MessageMouse msg(GetNormalWidget(),
140                         CFWL_MessageMouse::MouseCommand::kLeftButtonDown,
141                         dwFlags, FWLToClient(point));
142   SendMessageToFWLWidget(&msg);
143   return true;
144 }
145 
OnRButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)146 bool CXFA_FFTextEdit::OnRButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,
147                                     const CFX_PointF& point) {
148   if (!IsFocused()) {
149     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
150     UpdateFWLData();
151     InvalidateRect();
152   }
153   SetButtonDown(true);
154   CFWL_MessageMouse msg(nullptr,
155                         CFWL_MessageMouse::MouseCommand::kRightButtonDown,
156                         dwFlags, FWLToClient(point));
157   SendMessageToFWLWidget(&msg);
158   return true;
159 }
160 
OnRButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)161 bool CXFA_FFTextEdit::OnRButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,
162                                   const CFX_PointF& point) {
163   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
164     return false;
165 
166   GetDoc()->PopupMenu(this, point);
167   return true;
168 }
169 
OnSetFocus(CXFA_FFWidget * pOldWidget)170 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
171   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
172   if (!IsFocused()) {
173     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
174     UpdateFWLData();
175     InvalidateRect();
176   }
177   if (!CXFA_FFWidget::OnSetFocus(pOldWidget))
178     return false;
179 
180   CFWL_MessageSetFocus msg(GetNormalWidget());
181   SendMessageToFWLWidget(&msg);
182   return true;
183 }
184 
OnKillFocus(CXFA_FFWidget * pNewWidget)185 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
186   CFWL_MessageKillFocus msg(GetNormalWidget());
187   SendMessageToFWLWidget(&msg);
188 
189   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kFocused);
190   SetEditScrollOffset();
191   ProcessCommittedData();
192   UpdateFWLData();
193   InvalidateRect();
194 
195   if (!CXFA_FFWidget::OnKillFocus(pNewWidget))
196     return false;
197 
198   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
199   return true;
200 }
201 
CommitData()202 bool CXFA_FFTextEdit::CommitData() {
203   WideString wsText = ToEdit(GetNormalWidget())->GetText();
204   if (m_pNode->SetValue(XFA_ValuePicture::kEdit, wsText)) {
205     GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this);
206     return true;
207   }
208   ValidateNumberField(wsText);
209   return false;
210 }
211 
ValidateNumberField(const WideString & wsText)212 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
213   if (GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kNumericEdit)
214     return;
215 
216   CXFA_FFApp::CallbackIface* pAppProvider = GetAppProvider();
217   if (!pAppProvider)
218     return;
219 
220   WideString wsSomField = GetNode()->GetSOMExpression();
221   pAppProvider->MsgBox(
222       wsText + WideString::FromASCII(" can not contain ") + wsSomField,
223       pAppProvider->GetAppTitle(), static_cast<uint32_t>(AlertIcon::kError),
224       static_cast<uint32_t>(AlertButton::kOK));
225 }
226 
IsDataChanged()227 bool CXFA_FFTextEdit::IsDataChanged() {
228   return GetLayoutItem()->TestStatusBits(
229       XFA_WidgetStatus::kTextEditValueChanged);
230 }
231 
GetAlignment()232 uint32_t CXFA_FFTextEdit::GetAlignment() {
233   CXFA_Para* para = m_pNode->GetParaIfExists();
234   if (!para)
235     return 0;
236 
237   uint32_t dwExtendedStyle = 0;
238   switch (para->GetHorizontalAlign()) {
239     case XFA_AttributeValue::Center:
240       dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
241       break;
242     case XFA_AttributeValue::Justify:
243       dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
244       break;
245     case XFA_AttributeValue::JustifyAll:
246     case XFA_AttributeValue::Radix:
247       break;
248     case XFA_AttributeValue::Right:
249       dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
250       break;
251     default:
252       dwExtendedStyle |= FWL_STYLEEXT_EDT_HNear;
253       break;
254   }
255 
256   switch (para->GetVerticalAlign()) {
257     case XFA_AttributeValue::Middle:
258       dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
259       break;
260     case XFA_AttributeValue::Bottom:
261       dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
262       break;
263     default:
264       dwExtendedStyle |= FWL_STYLEEXT_EDT_VNear;
265       break;
266   }
267   return dwExtendedStyle;
268 }
269 
UpdateFWLData()270 bool CXFA_FFTextEdit::UpdateFWLData() {
271   CFWL_Edit* pEdit = ToEdit(GetNormalWidget());
272   if (!pEdit)
273     return false;
274 
275   XFA_ValuePicture eType = XFA_ValuePicture::kDisplay;
276   if (IsFocused())
277     eType = XFA_ValuePicture::kEdit;
278 
279   bool bUpdate = false;
280   if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kTextEdit &&
281       !m_pNode->GetNumberOfCells().has_value()) {
282     auto [elementType, iMaxChars] = m_pNode->GetMaxChars();
283     if (elementType == XFA_Element::ExData)
284       iMaxChars = eType == XFA_ValuePicture::kEdit ? iMaxChars : 0;
285     if (pEdit->GetLimit() != iMaxChars) {
286       pEdit->SetLimit(iMaxChars);
287       bUpdate = true;
288     }
289   } else if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kBarcode) {
290     int32_t nDataLen = 0;
291     if (eType == XFA_ValuePicture::kEdit) {
292       nDataLen = static_cast<CXFA_Barcode*>(m_pNode->GetUIChildNode())
293                      ->GetDataLength()
294                      .value_or(0);
295     }
296 
297     pEdit->SetLimit(nDataLen);
298     bUpdate = true;
299   }
300   WideString wsText = m_pNode->GetValue(eType);
301   WideString wsOldText = pEdit->GetText();
302   if (wsText != wsOldText || (eType == XFA_ValuePicture::kEdit && bUpdate)) {
303     pEdit->SetTextSkipNotify(wsText);
304     bUpdate = true;
305   }
306   if (bUpdate)
307     GetNormalWidget()->Update();
308 
309   return true;
310 }
311 
OnTextWillChange(CFWL_Widget * pWidget,CFWL_EventTextWillChange * event)312 void CXFA_FFTextEdit::OnTextWillChange(CFWL_Widget* pWidget,
313                                        CFWL_EventTextWillChange* event) {
314   GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
315 
316   CXFA_EventParam eParam(XFA_EVENT_Change);
317   eParam.m_wsChange = event->GetChangeText();
318   eParam.m_wsPrevText = event->GetPreviousText();
319   eParam.m_iSelStart = static_cast<int32_t>(event->GetSelectionStart());
320   eParam.m_iSelEnd = static_cast<int32_t>(event->GetSelectionEnd());
321   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
322 
323   // Copy the data back out of the EventParam and into the TextChanged event so
324   // it can propagate back to the calling widget.
325   event->SetCancelled(eParam.m_bCancelAction);
326   event->SetChangeText(eParam.m_wsChange);
327   event->SetSelectionStart(static_cast<size_t>(eParam.m_iSelStart));
328   event->SetSelectionEnd(static_cast<size_t>(eParam.m_iSelEnd));
329 }
330 
OnTextFull(CFWL_Widget * pWidget)331 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
332   CXFA_EventParam eParam(XFA_EVENT_Full);
333   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Full, &eParam);
334 }
335 
OnProcessMessage(CFWL_Message * pMessage)336 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
337   m_pOldDelegate->OnProcessMessage(pMessage);
338 }
339 
OnProcessEvent(CFWL_Event * pEvent)340 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
341   CXFA_FFField::OnProcessEvent(pEvent);
342   switch (pEvent->GetType()) {
343     case CFWL_Event::Type::TextWillChange:
344       OnTextWillChange(GetNormalWidget(),
345                        static_cast<CFWL_EventTextWillChange*>(pEvent));
346       break;
347     case CFWL_Event::Type::TextFull:
348       OnTextFull(GetNormalWidget());
349       break;
350     default:
351       break;
352   }
353   m_pOldDelegate->OnProcessEvent(pEvent);
354 }
355 
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)356 void CXFA_FFTextEdit::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
357                                    const CFX_Matrix& matrix) {
358   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
359 }
360 
CanUndo()361 bool CXFA_FFTextEdit::CanUndo() {
362   return ToEdit(GetNormalWidget())->CanUndo();
363 }
364 
CanRedo()365 bool CXFA_FFTextEdit::CanRedo() {
366   return ToEdit(GetNormalWidget())->CanRedo();
367 }
368 
CanCopy()369 bool CXFA_FFTextEdit::CanCopy() {
370   return ToEdit(GetNormalWidget())->HasSelection();
371 }
372 
CanCut()373 bool CXFA_FFTextEdit::CanCut() {
374   if (ToEdit(GetNormalWidget())->GetStyleExts() & FWL_STYLEEXT_EDT_ReadOnly)
375     return false;
376   return ToEdit(GetNormalWidget())->HasSelection();
377 }
378 
CanPaste()379 bool CXFA_FFTextEdit::CanPaste() {
380   return !(ToEdit(GetNormalWidget())->GetStyleExts() &
381            FWL_STYLEEXT_EDT_ReadOnly);
382 }
383 
CanSelectAll()384 bool CXFA_FFTextEdit::CanSelectAll() {
385   return ToEdit(GetNormalWidget())->GetTextLength() > 0;
386 }
387 
Undo()388 bool CXFA_FFTextEdit::Undo() {
389   return ToEdit(GetNormalWidget())->Undo();
390 }
391 
Redo()392 bool CXFA_FFTextEdit::Redo() {
393   return ToEdit(GetNormalWidget())->Redo();
394 }
395 
Copy()396 std::optional<WideString> CXFA_FFTextEdit::Copy() {
397   return ToEdit(GetNormalWidget())->Copy();
398 }
399 
Cut()400 std::optional<WideString> CXFA_FFTextEdit::Cut() {
401   return ToEdit(GetNormalWidget())->Cut();
402 }
403 
Paste(const WideString & wsPaste)404 bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
405   return ToEdit(GetNormalWidget())->Paste(wsPaste);
406 }
407 
SelectAll()408 void CXFA_FFTextEdit::SelectAll() {
409   ToEdit(GetNormalWidget())->SelectAll();
410 }
411 
Delete()412 void CXFA_FFTextEdit::Delete() {
413   ToEdit(GetNormalWidget())->ClearText();
414 }
415 
DeSelect()416 void CXFA_FFTextEdit::DeSelect() {
417   ToEdit(GetNormalWidget())->ClearSelection();
418 }
419 
GetText()420 WideString CXFA_FFTextEdit::GetText() {
421   return ToEdit(GetNormalWidget())->GetText();
422 }
423 
GetFormFieldType()424 FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
425   return FormFieldType::kXFA_TextField;
426 }
427