xref: /aosp_15_r20/external/pdfium/xfa/fxfa/cxfa_fftextedit.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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 "third_party/base/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   XFA_Element eType;
98   int32_t iMaxChars;
99   std::tie(eType, iMaxChars) = m_pNode->GetMaxChars();
100   if (eType == XFA_Element::ExData)
101     iMaxChars = 0;
102 
103   absl::optional<int32_t> numCells = m_pNode->GetNumberOfCells();
104   if (!numCells.has_value()) {
105     pWidget->SetLimit(iMaxChars);
106   } else if (numCells == 0) {
107     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
108     pWidget->SetLimit(iMaxChars > 0 ? iMaxChars : 1);
109   } else {
110     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
111     pWidget->SetLimit(numCells.value());
112   }
113 
114   dwExtendedStyle |= GetAlignment();
115   GetNormalWidget()->ModifyStyles(dwStyle, 0xFFFFFFFF);
116   GetNormalWidget()->ModifyStyleExts(dwExtendedStyle, 0xFFFFFFFF);
117 }
118 
AcceptsFocusOnButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point,CFWL_MessageMouse::MouseCommand command)119 bool CXFA_FFTextEdit::AcceptsFocusOnButtonDown(
120     Mask<XFA_FWL_KeyFlag> dwFlags,
121     const CFX_PointF& point,
122     CFWL_MessageMouse::MouseCommand command) {
123   if (command == CFWL_MessageMouse::MouseCommand::kRightButtonDown &&
124       !m_pNode->IsOpenAccess()) {
125     return false;
126   }
127   if (!PtInActiveRect(point))
128     return false;
129 
130   return true;
131 }
132 
OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)133 bool CXFA_FFTextEdit::OnLButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,
134                                     const CFX_PointF& point) {
135   if (!IsFocused()) {
136     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
137     UpdateFWLData();
138     InvalidateRect();
139   }
140   SetButtonDown(true);
141   CFWL_MessageMouse msg(GetNormalWidget(),
142                         CFWL_MessageMouse::MouseCommand::kLeftButtonDown,
143                         dwFlags, FWLToClient(point));
144   SendMessageToFWLWidget(&msg);
145   return true;
146 }
147 
OnRButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)148 bool CXFA_FFTextEdit::OnRButtonDown(Mask<XFA_FWL_KeyFlag> dwFlags,
149                                     const CFX_PointF& point) {
150   if (!IsFocused()) {
151     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
152     UpdateFWLData();
153     InvalidateRect();
154   }
155   SetButtonDown(true);
156   CFWL_MessageMouse msg(nullptr,
157                         CFWL_MessageMouse::MouseCommand::kRightButtonDown,
158                         dwFlags, FWLToClient(point));
159   SendMessageToFWLWidget(&msg);
160   return true;
161 }
162 
OnRButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,const CFX_PointF & point)163 bool CXFA_FFTextEdit::OnRButtonUp(Mask<XFA_FWL_KeyFlag> dwFlags,
164                                   const CFX_PointF& point) {
165   if (!CXFA_FFField::OnRButtonUp(dwFlags, point))
166     return false;
167 
168   GetDoc()->PopupMenu(this, point);
169   return true;
170 }
171 
OnSetFocus(CXFA_FFWidget * pOldWidget)172 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
173   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
174   if (!IsFocused()) {
175     GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kFocused);
176     UpdateFWLData();
177     InvalidateRect();
178   }
179   if (!CXFA_FFWidget::OnSetFocus(pOldWidget))
180     return false;
181 
182   CFWL_MessageSetFocus msg(GetNormalWidget());
183   SendMessageToFWLWidget(&msg);
184   return true;
185 }
186 
OnKillFocus(CXFA_FFWidget * pNewWidget)187 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
188   CFWL_MessageKillFocus msg(GetNormalWidget());
189   SendMessageToFWLWidget(&msg);
190 
191   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kFocused);
192   SetEditScrollOffset();
193   ProcessCommittedData();
194   UpdateFWLData();
195   InvalidateRect();
196 
197   if (!CXFA_FFWidget::OnKillFocus(pNewWidget))
198     return false;
199 
200   GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
201   return true;
202 }
203 
CommitData()204 bool CXFA_FFTextEdit::CommitData() {
205   WideString wsText = ToEdit(GetNormalWidget())->GetText();
206   if (m_pNode->SetValue(XFA_ValuePicture::kEdit, wsText)) {
207     GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this);
208     return true;
209   }
210   ValidateNumberField(wsText);
211   return false;
212 }
213 
ValidateNumberField(const WideString & wsText)214 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
215   if (GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kNumericEdit)
216     return;
217 
218   CXFA_FFApp::CallbackIface* pAppProvider = GetAppProvider();
219   if (!pAppProvider)
220     return;
221 
222   WideString wsSomField = GetNode()->GetSOMExpression();
223   pAppProvider->MsgBox(
224       wsText + WideString::FromASCII(" can not contain ") + wsSomField,
225       pAppProvider->GetAppTitle(), static_cast<uint32_t>(AlertIcon::kError),
226       static_cast<uint32_t>(AlertButton::kOK));
227 }
228 
IsDataChanged()229 bool CXFA_FFTextEdit::IsDataChanged() {
230   return GetLayoutItem()->TestStatusBits(
231       XFA_WidgetStatus::kTextEditValueChanged);
232 }
233 
GetAlignment()234 uint32_t CXFA_FFTextEdit::GetAlignment() {
235   CXFA_Para* para = m_pNode->GetParaIfExists();
236   if (!para)
237     return 0;
238 
239   uint32_t dwExtendedStyle = 0;
240   switch (para->GetHorizontalAlign()) {
241     case XFA_AttributeValue::Center:
242       dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
243       break;
244     case XFA_AttributeValue::Justify:
245       dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
246       break;
247     case XFA_AttributeValue::JustifyAll:
248     case XFA_AttributeValue::Radix:
249       break;
250     case XFA_AttributeValue::Right:
251       dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
252       break;
253     default:
254       dwExtendedStyle |= FWL_STYLEEXT_EDT_HNear;
255       break;
256   }
257 
258   switch (para->GetVerticalAlign()) {
259     case XFA_AttributeValue::Middle:
260       dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
261       break;
262     case XFA_AttributeValue::Bottom:
263       dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
264       break;
265     default:
266       dwExtendedStyle |= FWL_STYLEEXT_EDT_VNear;
267       break;
268   }
269   return dwExtendedStyle;
270 }
271 
UpdateFWLData()272 bool CXFA_FFTextEdit::UpdateFWLData() {
273   CFWL_Edit* pEdit = ToEdit(GetNormalWidget());
274   if (!pEdit)
275     return false;
276 
277   XFA_ValuePicture eType = XFA_ValuePicture::kDisplay;
278   if (IsFocused())
279     eType = XFA_ValuePicture::kEdit;
280 
281   bool bUpdate = false;
282   if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kTextEdit &&
283       !m_pNode->GetNumberOfCells().has_value()) {
284     XFA_Element elementType;
285     int32_t iMaxChars;
286     std::tie(elementType, iMaxChars) = m_pNode->GetMaxChars();
287     if (elementType == XFA_Element::ExData)
288       iMaxChars = eType == XFA_ValuePicture::kEdit ? iMaxChars : 0;
289     if (pEdit->GetLimit() != iMaxChars) {
290       pEdit->SetLimit(iMaxChars);
291       bUpdate = true;
292     }
293   } else if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kBarcode) {
294     int32_t nDataLen = 0;
295     if (eType == XFA_ValuePicture::kEdit) {
296       nDataLen = static_cast<CXFA_Barcode*>(m_pNode->GetUIChildNode())
297                      ->GetDataLength()
298                      .value_or(0);
299     }
300 
301     pEdit->SetLimit(nDataLen);
302     bUpdate = true;
303   }
304   WideString wsText = m_pNode->GetValue(eType);
305   WideString wsOldText = pEdit->GetText();
306   if (wsText != wsOldText || (eType == XFA_ValuePicture::kEdit && bUpdate)) {
307     pEdit->SetTextSkipNotify(wsText);
308     bUpdate = true;
309   }
310   if (bUpdate)
311     GetNormalWidget()->Update();
312 
313   return true;
314 }
315 
OnTextWillChange(CFWL_Widget * pWidget,CFWL_EventTextWillChange * event)316 void CXFA_FFTextEdit::OnTextWillChange(CFWL_Widget* pWidget,
317                                        CFWL_EventTextWillChange* event) {
318   GetLayoutItem()->SetStatusBits(XFA_WidgetStatus::kTextEditValueChanged);
319 
320   CXFA_EventParam eParam;
321   eParam.m_eType = XFA_EVENT_Change;
322   eParam.m_wsChange = event->GetChangeText();
323   eParam.m_wsPrevText = event->GetPreviousText();
324   eParam.m_iSelStart = static_cast<int32_t>(event->GetSelectionStart());
325   eParam.m_iSelEnd = static_cast<int32_t>(event->GetSelectionEnd());
326   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
327 
328   // Copy the data back out of the EventParam and into the TextChanged event so
329   // it can propagate back to the calling widget.
330   event->SetCancelled(eParam.m_bCancelAction);
331   event->SetChangeText(eParam.m_wsChange);
332   event->SetSelectionStart(static_cast<size_t>(eParam.m_iSelStart));
333   event->SetSelectionEnd(static_cast<size_t>(eParam.m_iSelEnd));
334 }
335 
OnTextFull(CFWL_Widget * pWidget)336 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
337   CXFA_EventParam eParam;
338   eParam.m_eType = XFA_EVENT_Full;
339   m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Full, &eParam);
340 }
341 
OnProcessMessage(CFWL_Message * pMessage)342 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
343   m_pOldDelegate->OnProcessMessage(pMessage);
344 }
345 
OnProcessEvent(CFWL_Event * pEvent)346 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
347   CXFA_FFField::OnProcessEvent(pEvent);
348   switch (pEvent->GetType()) {
349     case CFWL_Event::Type::TextWillChange:
350       OnTextWillChange(GetNormalWidget(),
351                        static_cast<CFWL_EventTextWillChange*>(pEvent));
352       break;
353     case CFWL_Event::Type::TextFull:
354       OnTextFull(GetNormalWidget());
355       break;
356     default:
357       break;
358   }
359   m_pOldDelegate->OnProcessEvent(pEvent);
360 }
361 
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)362 void CXFA_FFTextEdit::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
363                                    const CFX_Matrix& matrix) {
364   m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
365 }
366 
CanUndo()367 bool CXFA_FFTextEdit::CanUndo() {
368   return ToEdit(GetNormalWidget())->CanUndo();
369 }
370 
CanRedo()371 bool CXFA_FFTextEdit::CanRedo() {
372   return ToEdit(GetNormalWidget())->CanRedo();
373 }
374 
CanCopy()375 bool CXFA_FFTextEdit::CanCopy() {
376   return ToEdit(GetNormalWidget())->HasSelection();
377 }
378 
CanCut()379 bool CXFA_FFTextEdit::CanCut() {
380   if (ToEdit(GetNormalWidget())->GetStyleExts() & FWL_STYLEEXT_EDT_ReadOnly)
381     return false;
382   return ToEdit(GetNormalWidget())->HasSelection();
383 }
384 
CanPaste()385 bool CXFA_FFTextEdit::CanPaste() {
386   return !(ToEdit(GetNormalWidget())->GetStyleExts() &
387            FWL_STYLEEXT_EDT_ReadOnly);
388 }
389 
CanSelectAll()390 bool CXFA_FFTextEdit::CanSelectAll() {
391   return ToEdit(GetNormalWidget())->GetTextLength() > 0;
392 }
393 
Undo()394 bool CXFA_FFTextEdit::Undo() {
395   return ToEdit(GetNormalWidget())->Undo();
396 }
397 
Redo()398 bool CXFA_FFTextEdit::Redo() {
399   return ToEdit(GetNormalWidget())->Redo();
400 }
401 
Copy()402 absl::optional<WideString> CXFA_FFTextEdit::Copy() {
403   return ToEdit(GetNormalWidget())->Copy();
404 }
405 
Cut()406 absl::optional<WideString> CXFA_FFTextEdit::Cut() {
407   return ToEdit(GetNormalWidget())->Cut();
408 }
409 
Paste(const WideString & wsPaste)410 bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
411   return ToEdit(GetNormalWidget())->Paste(wsPaste);
412 }
413 
SelectAll()414 void CXFA_FFTextEdit::SelectAll() {
415   ToEdit(GetNormalWidget())->SelectAll();
416 }
417 
Delete()418 void CXFA_FFTextEdit::Delete() {
419   ToEdit(GetNormalWidget())->ClearText();
420 }
421 
DeSelect()422 void CXFA_FFTextEdit::DeSelect() {
423   ToEdit(GetNormalWidget())->ClearSelection();
424 }
425 
GetText()426 WideString CXFA_FFTextEdit::GetText() {
427   return ToEdit(GetNormalWidget())->GetText();
428 }
429 
GetFormFieldType()430 FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
431   return FormFieldType::kXFA_TextField;
432 }
433