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 "xfa/fxfa/cxfa_ffnotify.h"
8
9 #include <utility>
10
11 #include "third_party/base/ptr_util.h"
12 #include "xfa/fxfa/cxfa_ffapp.h"
13 #include "xfa/fxfa/cxfa_ffarc.h"
14 #include "xfa/fxfa/cxfa_ffbarcode.h"
15 #include "xfa/fxfa/cxfa_ffcheckbutton.h"
16 #include "xfa/fxfa/cxfa_ffcombobox.h"
17 #include "xfa/fxfa/cxfa_ffdatetimeedit.h"
18 #include "xfa/fxfa/cxfa_ffdoc.h"
19 #include "xfa/fxfa/cxfa_ffdocview.h"
20 #include "xfa/fxfa/cxfa_ffexclgroup.h"
21 #include "xfa/fxfa/cxfa_fffield.h"
22 #include "xfa/fxfa/cxfa_ffimage.h"
23 #include "xfa/fxfa/cxfa_ffimageedit.h"
24 #include "xfa/fxfa/cxfa_ffline.h"
25 #include "xfa/fxfa/cxfa_fflistbox.h"
26 #include "xfa/fxfa/cxfa_ffnumericedit.h"
27 #include "xfa/fxfa/cxfa_ffpageview.h"
28 #include "xfa/fxfa/cxfa_ffpasswordedit.h"
29 #include "xfa/fxfa/cxfa_ffpushbutton.h"
30 #include "xfa/fxfa/cxfa_ffrectangle.h"
31 #include "xfa/fxfa/cxfa_ffsignature.h"
32 #include "xfa/fxfa/cxfa_fftext.h"
33 #include "xfa/fxfa/cxfa_ffwidget.h"
34 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
35 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
36 #include "xfa/fxfa/cxfa_textlayout.h"
37 #include "xfa/fxfa/cxfa_textprovider.h"
38 #include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
39 #include "xfa/fxfa/parser/cxfa_barcode.h"
40 #include "xfa/fxfa/parser/cxfa_binditems.h"
41 #include "xfa/fxfa/parser/cxfa_button.h"
42 #include "xfa/fxfa/parser/cxfa_checkbutton.h"
43 #include "xfa/fxfa/parser/cxfa_node.h"
44 #include "xfa/fxfa/parser/cxfa_passwordedit.h"
45
CXFA_FFNotify(CXFA_FFDoc * pDoc)46 CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
47
~CXFA_FFNotify()48 CXFA_FFNotify::~CXFA_FFNotify() {}
49
OnPageEvent(CXFA_ViewLayoutItem * pSender,uint32_t dwEvent)50 void CXFA_FFNotify::OnPageEvent(CXFA_ViewLayoutItem* pSender,
51 uint32_t dwEvent) {
52 CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pSender->GetLayout());
53 if (pDocView)
54 pDocView->OnPageEvent(pSender, dwEvent);
55 }
56
OnWidgetListItemAdded(CXFA_Node * pSender,const WideString & wsLabel,int32_t iIndex)57 void CXFA_FFNotify::OnWidgetListItemAdded(CXFA_Node* pSender,
58 const WideString& wsLabel,
59 int32_t iIndex) {
60 if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
61 return;
62
63 CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
64 for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
65 if (pWidget->IsLoaded())
66 ToDropDown(ToField(pWidget))->InsertItem(wsLabel, iIndex);
67 }
68 }
69
OnWidgetListItemRemoved(CXFA_Node * pSender,int32_t iIndex)70 void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_Node* pSender,
71 int32_t iIndex) {
72 if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
73 return;
74
75 CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
76 for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
77 if (pWidget->IsLoaded())
78 ToDropDown(ToField(pWidget))->DeleteItem(iIndex);
79 }
80 }
81
OnCreateViewLayoutItem(CXFA_Node * pNode)82 std::unique_ptr<CXFA_FFPageView> CXFA_FFNotify::OnCreateViewLayoutItem(
83 CXFA_Node* pNode) {
84 if (pNode->GetElementType() != XFA_Element::PageArea)
85 return nullptr;
86
87 auto* pLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
88 return pdfium::MakeUnique<CXFA_FFPageView>(m_pDoc->GetDocView(pLayout),
89 pNode);
90 }
91
OnCreateContentLayoutItem(CXFA_Node * pNode)92 std::unique_ptr<CXFA_FFWidget> CXFA_FFNotify::OnCreateContentLayoutItem(
93 CXFA_Node* pNode) {
94 ASSERT(pNode->GetElementType() != XFA_Element::ContentArea);
95 ASSERT(pNode->GetElementType() != XFA_Element::PageArea);
96
97 // We only need to create the widget for certain types of objects.
98 if (!pNode->HasCreatedUIWidget())
99 return nullptr;
100
101 std::unique_ptr<CXFA_FFWidget> pWidget;
102 switch (pNode->GetFFWidgetType()) {
103 case XFA_FFWidgetType::kBarcode: {
104 CXFA_Node* child = pNode->GetUIChildNode();
105 if (child->GetElementType() != XFA_Element::Barcode)
106 return nullptr;
107
108 pWidget = pdfium::MakeUnique<CXFA_FFBarcode>(
109 pNode, static_cast<CXFA_Barcode*>(child));
110 break;
111 }
112 case XFA_FFWidgetType::kButton: {
113 CXFA_Node* child = pNode->GetUIChildNode();
114 if (child->GetElementType() != XFA_Element::Button)
115 return nullptr;
116
117 pWidget = pdfium::MakeUnique<CXFA_FFPushButton>(
118 pNode, static_cast<CXFA_Button*>(child));
119 break;
120 }
121 case XFA_FFWidgetType::kCheckButton: {
122 CXFA_Node* child = pNode->GetUIChildNode();
123 if (child->GetElementType() != XFA_Element::CheckButton)
124 return nullptr;
125
126 pWidget = pdfium::MakeUnique<CXFA_FFCheckButton>(
127 pNode, static_cast<CXFA_CheckButton*>(child));
128 break;
129 }
130 case XFA_FFWidgetType::kChoiceList: {
131 if (pNode->IsListBox())
132 pWidget = pdfium::MakeUnique<CXFA_FFListBox>(pNode);
133 else
134 pWidget = pdfium::MakeUnique<CXFA_FFComboBox>(pNode);
135 break;
136 }
137 case XFA_FFWidgetType::kDateTimeEdit:
138 pWidget = pdfium::MakeUnique<CXFA_FFDateTimeEdit>(pNode);
139 break;
140 case XFA_FFWidgetType::kImageEdit:
141 pWidget = pdfium::MakeUnique<CXFA_FFImageEdit>(pNode);
142 break;
143 case XFA_FFWidgetType::kNumericEdit:
144 pWidget = pdfium::MakeUnique<CXFA_FFNumericEdit>(pNode);
145 break;
146 case XFA_FFWidgetType::kPasswordEdit: {
147 CXFA_Node* child = pNode->GetUIChildNode();
148 if (child->GetElementType() != XFA_Element::PasswordEdit)
149 return nullptr;
150
151 pWidget = pdfium::MakeUnique<CXFA_FFPasswordEdit>(
152 pNode, static_cast<CXFA_PasswordEdit*>(child));
153 break;
154 }
155 case XFA_FFWidgetType::kSignature:
156 pWidget = pdfium::MakeUnique<CXFA_FFSignature>(pNode);
157 break;
158 case XFA_FFWidgetType::kTextEdit:
159 pWidget = pdfium::MakeUnique<CXFA_FFTextEdit>(pNode);
160 break;
161 case XFA_FFWidgetType::kArc:
162 pWidget = pdfium::MakeUnique<CXFA_FFArc>(pNode);
163 break;
164 case XFA_FFWidgetType::kLine:
165 pWidget = pdfium::MakeUnique<CXFA_FFLine>(pNode);
166 break;
167 case XFA_FFWidgetType::kRectangle:
168 pWidget = pdfium::MakeUnique<CXFA_FFRectangle>(pNode);
169 break;
170 case XFA_FFWidgetType::kText:
171 pWidget = pdfium::MakeUnique<CXFA_FFText>(pNode);
172 break;
173 case XFA_FFWidgetType::kImage:
174 pWidget = pdfium::MakeUnique<CXFA_FFImage>(pNode);
175 break;
176 case XFA_FFWidgetType::kSubform:
177 pWidget = pdfium::MakeUnique<CXFA_FFWidget>(pNode);
178 break;
179 case XFA_FFWidgetType::kExclGroup:
180 pWidget = pdfium::MakeUnique<CXFA_FFExclGroup>(pNode);
181 break;
182 case XFA_FFWidgetType::kNone:
183 return nullptr;
184 }
185 ASSERT(pWidget);
186 auto* pLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
187 pWidget->SetDocView(m_pDoc->GetDocView(pLayout));
188 return pWidget;
189 }
190
StartFieldDrawLayout(CXFA_Node * pItem,float * pCalcWidth,float * pCalcHeight)191 void CXFA_FFNotify::StartFieldDrawLayout(CXFA_Node* pItem,
192 float* pCalcWidth,
193 float* pCalcHeight) {
194 pItem->StartWidgetLayout(m_pDoc.Get(), pCalcWidth, pCalcHeight);
195 }
196
RunScript(CXFA_Script * script,CXFA_Node * item)197 bool CXFA_FFNotify::RunScript(CXFA_Script* script, CXFA_Node* item) {
198 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
199 if (!pDocView)
200 return false;
201
202 CXFA_EventParam EventParam;
203 EventParam.m_eType = XFA_EVENT_Unknown;
204
205 XFA_EventError iRet;
206 bool bRet;
207 std::tie(iRet, bRet) = item->ExecuteBoolScript(pDocView, script, &EventParam);
208 return iRet == XFA_EventError::kSuccess && bRet;
209 }
210
ExecEventByDeepFirst(CXFA_Node * pFormNode,XFA_EVENTTYPE eEventType,bool bIsFormReady,bool bRecursive)211 XFA_EventError CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
212 XFA_EVENTTYPE eEventType,
213 bool bIsFormReady,
214 bool bRecursive) {
215 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
216 if (!pDocView)
217 return XFA_EventError::kNotExist;
218 return pDocView->ExecEventActivityByDeepFirst(pFormNode, eEventType,
219 bIsFormReady, bRecursive);
220 }
221
AddCalcValidate(CXFA_Node * pNode)222 void CXFA_FFNotify::AddCalcValidate(CXFA_Node* pNode) {
223 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
224 if (!pDocView)
225 return;
226
227 pDocView->AddCalculateNode(pNode);
228 pDocView->AddValidateNode(pNode);
229 }
230
GetAppProvider()231 IXFA_AppProvider* CXFA_FFNotify::GetAppProvider() {
232 return m_pDoc->GetApp()->GetAppProvider();
233 }
234
GetWidgetHandler()235 CXFA_FFWidgetHandler* CXFA_FFNotify::GetWidgetHandler() {
236 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
237 return pDocView ? pDocView->GetWidgetHandler() : nullptr;
238 }
239
OpenDropDownList(CXFA_Node * pNode)240 void CXFA_FFNotify::OpenDropDownList(CXFA_Node* pNode) {
241 auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
242 CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
243 if (!pLayoutItem)
244 return;
245
246 CXFA_FFWidget* hWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem);
247 if (!hWidget)
248 return;
249
250 // SetFocusWidget() may destroy |hWidget| object by JS callback.
251 ObservedPtr<CXFA_FFWidget> pObservedWidget(hWidget);
252 CXFA_FFDoc* hDoc = GetHDOC();
253 hDoc->GetDocEnvironment()->SetFocusWidget(hDoc, hWidget);
254 if (!pObservedWidget)
255 return;
256
257 if (hWidget->GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
258 return;
259
260 if (!hWidget->IsLoaded())
261 return;
262
263 CXFA_FFDropDown* pDropDown = ToDropDown(ToField(hWidget));
264 CXFA_FFComboBox* pComboBox = ToComboBox(pDropDown);
265 if (!pComboBox)
266 return;
267
268 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
269 pDocView->LockUpdate();
270 pComboBox->OpenDropDownList();
271 pDocView->UnlockUpdate();
272 pDocView->UpdateDocView();
273 }
274
ResetData(CXFA_Node * pNode)275 void CXFA_FFNotify::ResetData(CXFA_Node* pNode) {
276 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
277 if (!pDocView)
278 return;
279
280 pDocView->ResetNode(pNode);
281 }
282
GetLayoutStatus()283 int32_t CXFA_FFNotify::GetLayoutStatus() {
284 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
285 return pDocView ? pDocView->GetLayoutStatus() : 0;
286 }
287
RunNodeInitialize(CXFA_Node * pNode)288 void CXFA_FFNotify::RunNodeInitialize(CXFA_Node* pNode) {
289 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
290 if (!pDocView)
291 return;
292
293 pDocView->AddNewFormNode(pNode);
294 }
295
RunSubformIndexChange(CXFA_Node * pSubformNode)296 void CXFA_FFNotify::RunSubformIndexChange(CXFA_Node* pSubformNode) {
297 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
298 if (!pDocView)
299 return;
300
301 pDocView->AddIndexChangedSubform(pSubformNode);
302 }
303
GetFocusWidgetNode()304 CXFA_Node* CXFA_FFNotify::GetFocusWidgetNode() {
305 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
306 return pDocView ? pDocView->GetFocusNode() : nullptr;
307 }
308
SetFocusWidgetNode(CXFA_Node * pNode)309 void CXFA_FFNotify::SetFocusWidgetNode(CXFA_Node* pNode) {
310 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
311 if (!pDocView)
312 return;
313 pDocView->SetFocusNode(pNode);
314 }
315
OnNodeReady(CXFA_Node * pNode)316 void CXFA_FFNotify::OnNodeReady(CXFA_Node* pNode) {
317 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
318 if (!pDocView)
319 return;
320
321 if (pNode->HasCreatedUIWidget()) {
322 pNode->SetWidgetReady();
323 return;
324 }
325
326 switch (pNode->GetElementType()) {
327 case XFA_Element::BindItems:
328 pDocView->AddBindItem(static_cast<CXFA_BindItems*>(pNode));
329 break;
330 case XFA_Element::Validate:
331 pNode->SetFlag(XFA_NodeFlag_NeedsInitApp);
332 break;
333 default:
334 break;
335 }
336 }
337
OnValueChanging(CXFA_Node * pSender,XFA_Attribute eAttr)338 void CXFA_FFNotify::OnValueChanging(CXFA_Node* pSender, XFA_Attribute eAttr) {
339 if (eAttr != XFA_Attribute::Presence)
340 return;
341 if (pSender->GetPacketType() == XFA_PacketType::Datasets)
342 return;
343 if (!pSender->IsFormContainer())
344 return;
345
346 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
347 if (!pDocView)
348 return;
349 if (pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End)
350 return;
351
352 CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
353 for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
354 if (pWidget->IsLoaded())
355 pWidget->InvalidateRect();
356 }
357 }
358
OnValueChanged(CXFA_Node * pSender,XFA_Attribute eAttr,CXFA_Node * pParentNode,CXFA_Node * pWidgetNode)359 void CXFA_FFNotify::OnValueChanged(CXFA_Node* pSender,
360 XFA_Attribute eAttr,
361 CXFA_Node* pParentNode,
362 CXFA_Node* pWidgetNode) {
363 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
364 if (!pDocView)
365 return;
366
367 if (pSender->GetPacketType() != XFA_PacketType::Form) {
368 if (eAttr == XFA_Attribute::Value)
369 pDocView->AddCalculateNodeNotify(pSender);
370 return;
371 }
372
373 XFA_Element eType = pParentNode->GetElementType();
374 bool bIsContainerNode = pParentNode->IsContainerNode();
375 bool bUpdateProperty = false;
376 pDocView->SetChangeMark();
377 switch (eType) {
378 case XFA_Element::Caption: {
379 CXFA_TextLayout* pCapOut = pWidgetNode->GetCaptionTextLayout();
380 if (!pCapOut)
381 return;
382
383 pCapOut->Unload();
384 break;
385 }
386 case XFA_Element::Ui:
387 case XFA_Element::Para:
388 bUpdateProperty = true;
389 break;
390 default:
391 break;
392 }
393 if (bIsContainerNode && eAttr == XFA_Attribute::Access)
394 bUpdateProperty = true;
395
396 if (eAttr == XFA_Attribute::Value) {
397 pDocView->AddCalculateNodeNotify(pSender);
398 if (eType == XFA_Element::Value || bIsContainerNode) {
399 if (bIsContainerNode) {
400 m_pDoc->GetDocView()->UpdateUIDisplay(pWidgetNode, nullptr);
401 pDocView->AddCalculateNode(pWidgetNode);
402 pDocView->AddValidateNode(pWidgetNode);
403 } else if (pWidgetNode->GetParent()->GetElementType() ==
404 XFA_Element::ExclGroup) {
405 m_pDoc->GetDocView()->UpdateUIDisplay(pWidgetNode, nullptr);
406 }
407 return;
408 }
409 }
410
411 CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pWidgetNode);
412 for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
413 if (!pWidget->IsLoaded())
414 continue;
415
416 if (bUpdateProperty)
417 pWidget->UpdateWidgetProperty();
418 pWidget->PerformLayout();
419 pWidget->InvalidateRect();
420 }
421 }
422
OnContainerChanged(CXFA_Node * pNode)423 void CXFA_FFNotify::OnContainerChanged(CXFA_Node* pNode) {
424 m_pDoc->GetXFADoc()->GetLayoutProcessor()->AddChangedContainer(pNode);
425 }
426
OnChildAdded(CXFA_Node * pSender)427 void CXFA_FFNotify::OnChildAdded(CXFA_Node* pSender) {
428 if (!pSender->IsFormContainer())
429 return;
430
431 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
432 if (!pDocView)
433 return;
434
435 bool bLayoutReady =
436 !(pDocView->m_bInLayoutStatus) &&
437 (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
438 if (bLayoutReady)
439 m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
440 }
441
OnChildRemoved()442 void CXFA_FFNotify::OnChildRemoved() {
443 CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
444 if (!pDocView)
445 return;
446
447 bool bLayoutReady =
448 !(pDocView->m_bInLayoutStatus) &&
449 (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
450 if (bLayoutReady)
451 m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
452 }
453
OnLayoutItemAdded(CXFA_LayoutProcessor * pLayout,CXFA_LayoutItem * pSender,int32_t iPageIdx,uint32_t dwStatus)454 void CXFA_FFNotify::OnLayoutItemAdded(CXFA_LayoutProcessor* pLayout,
455 CXFA_LayoutItem* pSender,
456 int32_t iPageIdx,
457 uint32_t dwStatus) {
458 CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
459 if (!pDocView)
460 return;
461
462 CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
463 if (!pWidget)
464 return;
465
466 CXFA_FFPageView* pNewPageView = pDocView->GetPageView(iPageIdx);
467 uint32_t dwFilter = XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable |
468 XFA_WidgetStatus_Printable;
469 pWidget->ModifyStatus(dwStatus, dwFilter);
470 CXFA_FFPageView* pPrePageView = pWidget->GetPageView();
471 if (pPrePageView != pNewPageView ||
472 (dwStatus & (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) ==
473 (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) {
474 pWidget->SetPageView(pNewPageView);
475 m_pDoc->GetDocEnvironment()->WidgetPostAdd(pWidget);
476 }
477 if (pDocView->GetLayoutStatus() != XFA_DOCVIEW_LAYOUTSTATUS_End ||
478 !(dwStatus & XFA_WidgetStatus_Visible)) {
479 return;
480 }
481 if (pWidget->IsLoaded()) {
482 if (pWidget->GetWidgetRect() != pWidget->RecacheWidgetRect())
483 pWidget->PerformLayout();
484 } else {
485 pWidget->LoadWidget();
486 }
487 pWidget->InvalidateRect();
488 }
489
OnLayoutItemRemoving(CXFA_LayoutProcessor * pLayout,CXFA_LayoutItem * pSender)490 void CXFA_FFNotify::OnLayoutItemRemoving(CXFA_LayoutProcessor* pLayout,
491 CXFA_LayoutItem* pSender) {
492 CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
493 if (!pDocView)
494 return;
495
496 CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
497 if (!pWidget)
498 return;
499
500 pDocView->DeleteLayoutItem(pWidget);
501 m_pDoc->GetDocEnvironment()->WidgetPreRemove(pWidget);
502 pWidget->InvalidateRect();
503 }
504