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_ffdocview.h"
8 
9 #include <set>
10 #include <utility>
11 
12 #include "core/fxcrt/fx_extension.h"
13 #include "fxjs/xfa/cfxjse_engine.h"
14 #include "fxjs/xfa/cjx_object.h"
15 #include "third_party/base/ptr_util.h"
16 #include "third_party/base/stl_util.h"
17 #include "xfa/fxfa/cxfa_ffapp.h"
18 #include "xfa/fxfa/cxfa_ffbarcode.h"
19 #include "xfa/fxfa/cxfa_ffcheckbutton.h"
20 #include "xfa/fxfa/cxfa_ffdoc.h"
21 #include "xfa/fxfa/cxfa_ffexclgroup.h"
22 #include "xfa/fxfa/cxfa_fffield.h"
23 #include "xfa/fxfa/cxfa_ffimage.h"
24 #include "xfa/fxfa/cxfa_ffimageedit.h"
25 #include "xfa/fxfa/cxfa_ffpageview.h"
26 #include "xfa/fxfa/cxfa_ffpushbutton.h"
27 #include "xfa/fxfa/cxfa_ffsignature.h"
28 #include "xfa/fxfa/cxfa_fftext.h"
29 #include "xfa/fxfa/cxfa_ffwidget.h"
30 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
31 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
32 #include "xfa/fxfa/cxfa_readynodeiterator.h"
33 #include "xfa/fxfa/cxfa_textprovider.h"
34 #include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
35 #include "xfa/fxfa/parser/cxfa_acrobat.h"
36 #include "xfa/fxfa/parser/cxfa_binditems.h"
37 #include "xfa/fxfa/parser/cxfa_calculate.h"
38 #include "xfa/fxfa/parser/cxfa_pageset.h"
39 #include "xfa/fxfa/parser/cxfa_present.h"
40 #include "xfa/fxfa/parser/cxfa_subform.h"
41 #include "xfa/fxfa/parser/cxfa_validate.h"
42 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
43 #include "xfa/fxfa/parser/xfa_utils.h"
44 
45 const XFA_AttributeValue gs_EventActivity[] = {
46     XFA_AttributeValue::Click,      XFA_AttributeValue::Change,
47     XFA_AttributeValue::DocClose,   XFA_AttributeValue::DocReady,
48     XFA_AttributeValue::Enter,      XFA_AttributeValue::Exit,
49     XFA_AttributeValue::Full,       XFA_AttributeValue::IndexChange,
50     XFA_AttributeValue::Initialize, XFA_AttributeValue::MouseDown,
51     XFA_AttributeValue::MouseEnter, XFA_AttributeValue::MouseExit,
52     XFA_AttributeValue::MouseUp,    XFA_AttributeValue::PostExecute,
53     XFA_AttributeValue::PostOpen,   XFA_AttributeValue::PostPrint,
54     XFA_AttributeValue::PostSave,   XFA_AttributeValue::PostSign,
55     XFA_AttributeValue::PostSubmit, XFA_AttributeValue::PreExecute,
56     XFA_AttributeValue::PreOpen,    XFA_AttributeValue::PrePrint,
57     XFA_AttributeValue::PreSave,    XFA_AttributeValue::PreSign,
58     XFA_AttributeValue::PreSubmit,  XFA_AttributeValue::Ready,
59     XFA_AttributeValue::Unknown,
60 };
61 
CXFA_FFDocView(CXFA_FFDoc * pDoc)62 CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
63 
64 CXFA_FFDocView::~CXFA_FFDocView() = default;
65 
InitLayout(CXFA_Node * pNode)66 void CXFA_FFDocView::InitLayout(CXFA_Node* pNode) {
67   RunBindItems();
68   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Initialize, false, true);
69   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_IndexChange, false, true);
70 }
71 
StartLayout()72 int32_t CXFA_FFDocView::StartLayout() {
73   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
74   m_pDoc->GetXFADoc()->DoProtoMerge();
75   m_pDoc->GetXFADoc()->DoDataMerge();
76   m_pXFADocLayout = GetXFALayout();
77 
78   int32_t iStatus = m_pXFADocLayout->StartLayout(false);
79   if (iStatus < 0)
80     return iStatus;
81 
82   CXFA_Node* pRootItem =
83       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
84   if (!pRootItem)
85     return iStatus;
86 
87   InitLayout(pRootItem);
88   InitCalculate(pRootItem);
89   InitValidate(pRootItem);
90 
91   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, true, true);
92   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
93   return iStatus;
94 }
95 
DoLayout()96 int32_t CXFA_FFDocView::DoLayout() {
97   int32_t iStatus = m_pXFADocLayout->DoLayout();
98   if (iStatus != 100)
99     return iStatus;
100 
101   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Doing;
102   return iStatus;
103 }
104 
StopLayout()105 void CXFA_FFDocView::StopLayout() {
106   CXFA_Node* pRootItem =
107       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
108   if (!pRootItem)
109     return;
110 
111   CXFA_Subform* pSubformNode =
112       pRootItem->GetChild<CXFA_Subform>(0, XFA_Element::Subform, false);
113   if (!pSubformNode)
114     return;
115 
116   CXFA_PageSet* pPageSetNode =
117       pSubformNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
118   if (!pPageSetNode)
119     return;
120 
121   RunCalculateWidgets();
122   RunValidate();
123 
124   InitLayout(pPageSetNode);
125   InitCalculate(pPageSetNode);
126   InitValidate(pPageSetNode);
127 
128   ExecEventActivityByDeepFirst(pPageSetNode, XFA_EVENT_Ready, true, true);
129   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
130   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocReady, false, true);
131 
132   RunCalculateWidgets();
133   RunValidate();
134 
135   if (RunLayout())
136     ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
137 
138   m_CalculateNodes.clear();
139   if (m_pFocusNode && !m_pFocusWidget)
140     SetFocusNode(m_pFocusNode.Get());
141 
142   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_End;
143 }
144 
ShowNullTestMsg()145 void CXFA_FFDocView::ShowNullTestMsg() {
146   int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrNullTestMsg);
147   CXFA_FFApp* pApp = m_pDoc->GetApp();
148   IXFA_AppProvider* pAppProvider = pApp->GetAppProvider();
149   if (pAppProvider && iCount) {
150     int32_t iRemain = iCount > 7 ? iCount - 7 : 0;
151     iCount -= iRemain;
152     WideString wsMsg;
153     for (int32_t i = 0; i < iCount; i++)
154       wsMsg += m_arrNullTestMsg[i] + L"\n";
155 
156     if (iRemain > 0) {
157       wsMsg += L"\n" + WideString::Format(
158                            L"Message limit exceeded. Remaining %d "
159                            L"validation errors not reported.",
160                            iRemain);
161     }
162     pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(),
163                          static_cast<uint32_t>(AlertIcon::kStatus),
164                          static_cast<uint32_t>(AlertButton::kOK));
165   }
166   m_arrNullTestMsg.clear();
167 }
168 
UpdateDocView()169 void CXFA_FFDocView::UpdateDocView() {
170   if (IsUpdateLocked())
171     return;
172 
173   LockUpdate();
174   while (!m_NewAddedNodes.empty()) {
175     CXFA_Node* pNode = m_NewAddedNodes.front();
176     m_NewAddedNodes.pop_front();
177     InitCalculate(pNode);
178     InitValidate(pNode);
179     ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Ready, true, true);
180   }
181 
182   RunSubformIndexChange();
183   RunCalculateWidgets();
184   RunValidate();
185 
186   ShowNullTestMsg();
187 
188   if (RunLayout() && m_bLayoutEvent)
189     RunEventLayoutReady();
190 
191   m_bLayoutEvent = false;
192   m_CalculateNodes.clear();
193   UnlockUpdate();
194 }
195 
UpdateUIDisplay(CXFA_Node * pNode,CXFA_FFWidget * pExcept)196 void CXFA_FFDocView::UpdateUIDisplay(CXFA_Node* pNode, CXFA_FFWidget* pExcept) {
197   CXFA_FFWidget* pWidget = GetWidgetForNode(pNode);
198   CXFA_FFWidget* pNext = nullptr;
199   for (; pWidget; pWidget = pNext) {
200     pNext = pWidget->GetNextFFWidget();
201     if (pWidget == pExcept || !pWidget->IsLoaded() ||
202         (pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton &&
203          pWidget->IsFocused())) {
204       continue;
205     }
206     ObservedPtr<CXFA_FFWidget> pWatched(pWidget);
207     ObservedPtr<CXFA_FFWidget> pWatchedNext(pNext);
208     pWatched->UpdateFWLData();
209     if (pWatched)
210       pWatched->InvalidateRect();
211     if (!pWatchedNext)
212       break;
213   }
214 }
215 
CountPageViews() const216 int32_t CXFA_FFDocView::CountPageViews() const {
217   return m_pXFADocLayout ? m_pXFADocLayout->CountPages() : 0;
218 }
219 
GetPageView(int32_t nIndex) const220 CXFA_FFPageView* CXFA_FFDocView::GetPageView(int32_t nIndex) const {
221   if (!m_pXFADocLayout)
222     return nullptr;
223   auto* pPage = m_pXFADocLayout->GetPage(nIndex);
224   return pPage ? pPage->GetPageView() : nullptr;
225 }
226 
GetXFALayout() const227 CXFA_LayoutProcessor* CXFA_FFDocView::GetXFALayout() const {
228   return CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
229 }
230 
ResetSingleNodeData(CXFA_Node * pNode)231 bool CXFA_FFDocView::ResetSingleNodeData(CXFA_Node* pNode) {
232   XFA_Element eType = pNode->GetElementType();
233   if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
234     return false;
235 
236   pNode->ResetData();
237   UpdateUIDisplay(pNode, nullptr);
238   CXFA_Validate* validate = pNode->GetValidateIfExists();
239   if (!validate)
240     return true;
241 
242   AddValidateNode(pNode);
243   validate->SetFlag(XFA_NodeFlag_NeedsInitApp);
244   return true;
245 }
246 
ResetNode(CXFA_Node * pNode)247 void CXFA_FFDocView::ResetNode(CXFA_Node* pNode) {
248   m_bLayoutEvent = true;
249   bool bChanged = false;
250   CXFA_Node* pFormNode = nullptr;
251   if (pNode) {
252     bChanged = ResetSingleNodeData(pNode);
253     pFormNode = pNode;
254   } else {
255     pFormNode = GetRootSubform();
256   }
257   if (!pFormNode)
258     return;
259 
260   if (pFormNode->GetElementType() != XFA_Element::Field &&
261       pFormNode->GetElementType() != XFA_Element::ExclGroup) {
262     CXFA_ReadyNodeIterator it(pFormNode);
263     while (CXFA_Node* next_node = it.MoveToNext()) {
264       bChanged |= ResetSingleNodeData(next_node);
265       if (next_node->GetElementType() == XFA_Element::ExclGroup)
266         it.SkipTree();
267     }
268   }
269   if (bChanged)
270     m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
271 }
272 
GetWidgetForNode(CXFA_Node * node)273 CXFA_FFWidget* CXFA_FFDocView::GetWidgetForNode(CXFA_Node* node) {
274   return GetFFWidget(ToContentLayoutItem(GetXFALayout()->GetLayoutItem(node)));
275 }
276 
GetWidgetHandler()277 CXFA_FFWidgetHandler* CXFA_FFDocView::GetWidgetHandler() {
278   if (!m_pWidgetHandler)
279     m_pWidgetHandler = pdfium::MakeUnique<CXFA_FFWidgetHandler>(this);
280   return m_pWidgetHandler.get();
281 }
282 
283 std::unique_ptr<CXFA_ReadyNodeIterator>
CreateReadyNodeIterator()284 CXFA_FFDocView::CreateReadyNodeIterator() {
285   CXFA_Subform* pFormRoot = GetRootSubform();
286   return pFormRoot ? pdfium::MakeUnique<CXFA_ReadyNodeIterator>(pFormRoot)
287                    : nullptr;
288 }
289 
SetFocus(CXFA_FFWidget * pNewFocus)290 bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* pNewFocus) {
291   if (pNewFocus == m_pFocusWidget)
292     return false;
293 
294   ObservedPtr<CXFA_FFWidget> pNewWatched(pNewFocus);
295   if (m_pFocusWidget) {
296     CXFA_ContentLayoutItem* pItem = m_pFocusWidget->GetLayoutItem();
297     if (pItem->TestStatusBits(XFA_WidgetStatus_Visible) &&
298         !pItem->TestStatusBits(XFA_WidgetStatus_Focused)) {
299       if (!m_pFocusWidget->IsLoaded())
300         m_pFocusWidget->LoadWidget();
301       if (!m_pFocusWidget->OnSetFocus(m_pFocusWidget.Get()))
302         m_pFocusWidget.Reset();
303     }
304   }
305   if (m_pFocusWidget) {
306     if (!m_pFocusWidget->OnKillFocus(pNewWatched.Get()))
307       return false;
308   }
309 
310   if (pNewWatched) {
311     if (pNewWatched->GetLayoutItem()->TestStatusBits(
312             XFA_WidgetStatus_Visible)) {
313       if (!pNewWatched->IsLoaded())
314         pNewWatched->LoadWidget();
315       if (!pNewWatched->OnSetFocus(m_pFocusWidget.Get()))
316         pNewWatched.Reset();
317     }
318   }
319   if (pNewWatched) {
320     CXFA_Node* node = pNewWatched->GetNode();
321     m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
322     m_pFocusWidget.Reset(pNewWatched.Get());
323   } else {
324     m_pFocusNode.Reset();
325     m_pFocusWidget.Reset();
326   }
327 
328   return true;
329 }
330 
SetFocusNode(CXFA_Node * node)331 void CXFA_FFDocView::SetFocusNode(CXFA_Node* node) {
332   CXFA_FFWidget* pNewFocus = node ? GetWidgetForNode(node) : nullptr;
333   if (!SetFocus(pNewFocus))
334     return;
335 
336   m_pFocusNode = node;
337   if (m_iStatus != XFA_DOCVIEW_LAYOUTSTATUS_End)
338     return;
339 
340   m_pDoc->GetDocEnvironment()->SetFocusWidget(m_pDoc.Get(),
341                                               m_pFocusWidget.Get());
342 }
343 
DeleteLayoutItem(CXFA_FFWidget * pWidget)344 void CXFA_FFDocView::DeleteLayoutItem(CXFA_FFWidget* pWidget) {
345   if (m_pFocusNode != pWidget->GetNode())
346     return;
347 
348   m_pFocusNode.Reset();
349   m_pFocusWidget.Reset();
350 }
351 
XFA_ProcessEvent(CXFA_FFDocView * pDocView,CXFA_Node * pNode,CXFA_EventParam * pParam)352 static XFA_EventError XFA_ProcessEvent(CXFA_FFDocView* pDocView,
353                                        CXFA_Node* pNode,
354                                        CXFA_EventParam* pParam) {
355   if (!pParam || pParam->m_eType == XFA_EVENT_Unknown)
356     return XFA_EventError::kNotExist;
357   if (pNode && pNode->GetElementType() == XFA_Element::Draw)
358     return XFA_EventError::kNotExist;
359 
360   switch (pParam->m_eType) {
361     case XFA_EVENT_Calculate:
362       return pNode->ProcessCalculate(pDocView);
363     case XFA_EVENT_Validate:
364       if (pDocView->GetDoc()->GetDocEnvironment()->IsValidationsEnabled(
365               pDocView->GetDoc())) {
366         return pNode->ProcessValidate(pDocView, 0x01);
367       }
368       return XFA_EventError::kDisabled;
369     case XFA_EVENT_InitCalculate: {
370       CXFA_Calculate* calc = pNode->GetCalculateIfExists();
371       if (!calc)
372         return XFA_EventError::kNotExist;
373       if (pNode->IsUserInteractive())
374         return XFA_EventError::kDisabled;
375 
376       return pNode->ExecuteScript(pDocView, calc->GetScriptIfExists(), pParam);
377     }
378     default:
379       return pNode->ProcessEvent(pDocView, gs_EventActivity[pParam->m_eType],
380                                  pParam);
381   }
382 }
383 
ExecEventActivityByDeepFirst(CXFA_Node * pFormNode,XFA_EVENTTYPE eEventType,bool bIsFormReady,bool bRecursive)384 XFA_EventError CXFA_FFDocView::ExecEventActivityByDeepFirst(
385     CXFA_Node* pFormNode,
386     XFA_EVENTTYPE eEventType,
387     bool bIsFormReady,
388     bool bRecursive) {
389   if (!pFormNode)
390     return XFA_EventError::kNotExist;
391 
392   XFA_Element elementType = pFormNode->GetElementType();
393   if (elementType == XFA_Element::Field) {
394     if (eEventType == XFA_EVENT_IndexChange)
395       return XFA_EventError::kNotExist;
396 
397     if (!pFormNode->IsWidgetReady())
398       return XFA_EventError::kNotExist;
399 
400     CXFA_EventParam eParam;
401     eParam.m_eType = eEventType;
402     eParam.m_pTarget = pFormNode;
403     eParam.m_bIsFormReady = bIsFormReady;
404     return XFA_ProcessEvent(this, pFormNode, &eParam);
405   }
406 
407   XFA_EventError iRet = XFA_EventError::kNotExist;
408   if (bRecursive) {
409     for (CXFA_Node* pNode = pFormNode->GetFirstContainerChild(); pNode;
410          pNode = pNode->GetNextContainerSibling()) {
411       elementType = pNode->GetElementType();
412       if (elementType != XFA_Element::Variables &&
413           elementType != XFA_Element::Draw) {
414         XFA_EventErrorAccumulate(
415             &iRet, ExecEventActivityByDeepFirst(pNode, eEventType, bIsFormReady,
416                                                 bRecursive));
417       }
418     }
419   }
420   if (!pFormNode->IsWidgetReady())
421     return iRet;
422 
423   CXFA_EventParam eParam;
424   eParam.m_eType = eEventType;
425   eParam.m_pTarget = pFormNode;
426   eParam.m_bIsFormReady = bIsFormReady;
427 
428   XFA_EventErrorAccumulate(&iRet, XFA_ProcessEvent(this, pFormNode, &eParam));
429   return iRet;
430 }
431 
GetWidgetByName(const WideString & wsName,CXFA_FFWidget * pRefWidget)432 CXFA_FFWidget* CXFA_FFDocView::GetWidgetByName(const WideString& wsName,
433                                                CXFA_FFWidget* pRefWidget) {
434   CFXJSE_Engine* pScriptContext = m_pDoc->GetXFADoc()->GetScriptContext();
435   CXFA_Node* pRefNode = nullptr;
436   if (pRefWidget) {
437     CXFA_Node* node = pRefWidget->GetNode();
438     pRefNode = node->IsWidgetReady() ? node : nullptr;
439   }
440   WideString wsExpression = (!pRefNode ? L"$form." : L"") + wsName;
441 
442   XFA_RESOLVENODE_RS resolveNodeRS;
443   constexpr uint32_t kStyle = XFA_RESOLVENODE_Children |
444                               XFA_RESOLVENODE_Properties |
445                               XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent;
446   if (!pScriptContext->ResolveObjects(pRefNode, wsExpression.AsStringView(),
447                                       &resolveNodeRS, kStyle, nullptr)) {
448     return nullptr;
449   }
450 
451   if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
452     CXFA_Node* pNode = resolveNodeRS.objects.front()->AsNode();
453     if (pNode && pNode->IsWidgetReady())
454       return GetWidgetForNode(pNode);
455   }
456   return nullptr;
457 }
458 
OnPageEvent(CXFA_ViewLayoutItem * pSender,uint32_t dwEvent)459 void CXFA_FFDocView::OnPageEvent(CXFA_ViewLayoutItem* pSender,
460                                  uint32_t dwEvent) {
461   CXFA_FFPageView* pFFPageView = pSender ? pSender->GetPageView() : nullptr;
462   m_pDoc->GetDocEnvironment()->PageViewEvent(pFFPageView, dwEvent);
463 }
464 
InvalidateRect(CXFA_FFPageView * pPageView,const CFX_RectF & rtInvalidate)465 void CXFA_FFDocView::InvalidateRect(CXFA_FFPageView* pPageView,
466                                     const CFX_RectF& rtInvalidate) {
467   m_pDoc->GetDocEnvironment()->InvalidateRect(pPageView, rtInvalidate);
468 }
469 
RunLayout()470 bool CXFA_FFDocView::RunLayout() {
471   LockUpdate();
472   m_bInLayoutStatus = true;
473   if (!m_pXFADocLayout->IncrementLayout() &&
474       m_pXFADocLayout->StartLayout(false) < 100) {
475     m_pXFADocLayout->DoLayout();
476     UnlockUpdate();
477     m_bInLayoutStatus = false;
478     m_pDoc->GetDocEnvironment()->PageViewEvent(nullptr,
479                                                XFA_PAGEVIEWEVENT_StopLayout);
480     return true;
481   }
482 
483   m_bInLayoutStatus = false;
484   m_pDoc->GetDocEnvironment()->PageViewEvent(nullptr,
485                                              XFA_PAGEVIEWEVENT_StopLayout);
486   UnlockUpdate();
487   return false;
488 }
489 
RunSubformIndexChange()490 void CXFA_FFDocView::RunSubformIndexChange() {
491   std::set<CXFA_Node*> seen;
492   while (!m_IndexChangedSubforms.empty()) {
493     CXFA_Node* pSubformNode = m_IndexChangedSubforms.front();
494     m_IndexChangedSubforms.pop_front();
495     bool bInserted = seen.insert(pSubformNode).second;
496     if (!bInserted || !pSubformNode->IsWidgetReady())
497       continue;
498 
499     CXFA_EventParam eParam;
500     eParam.m_eType = XFA_EVENT_IndexChange;
501     eParam.m_pTarget = pSubformNode;
502     pSubformNode->ProcessEvent(this, XFA_AttributeValue::IndexChange, &eParam);
503   }
504 }
505 
AddNewFormNode(CXFA_Node * pNode)506 void CXFA_FFDocView::AddNewFormNode(CXFA_Node* pNode) {
507   m_NewAddedNodes.push_back(pNode);
508   InitLayout(pNode);
509 }
510 
AddIndexChangedSubform(CXFA_Node * pNode)511 void CXFA_FFDocView::AddIndexChangedSubform(CXFA_Node* pNode) {
512   ASSERT(pNode->GetElementType() == XFA_Element::Subform);
513   if (!pdfium::ContainsValue(m_IndexChangedSubforms, pNode))
514     m_IndexChangedSubforms.push_back(pNode);
515 }
516 
RunDocClose()517 void CXFA_FFDocView::RunDocClose() {
518   CXFA_Node* pRootItem =
519       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
520   if (!pRootItem)
521     return;
522 
523   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocClose, false, true);
524 }
525 
AddCalculateNode(CXFA_Node * node)526 void CXFA_FFDocView::AddCalculateNode(CXFA_Node* node) {
527   CXFA_Node* pCurrentNode =
528       !m_CalculateNodes.empty() ? m_CalculateNodes.back() : nullptr;
529   if (pCurrentNode != node)
530     m_CalculateNodes.push_back(node);
531 }
532 
AddCalculateNodeNotify(CXFA_Node * pNodeChange)533 void CXFA_FFDocView::AddCalculateNodeNotify(CXFA_Node* pNodeChange) {
534   CXFA_CalcData* pGlobalData = pNodeChange->JSObject()->GetCalcData();
535   if (!pGlobalData)
536     return;
537 
538   for (auto* pResult : pGlobalData->m_Globals) {
539     if (!pResult->HasRemovedChildren() && pResult->IsWidgetReady())
540       AddCalculateNode(pResult);
541   }
542 }
543 
RunCalculateRecursive(size_t index)544 size_t CXFA_FFDocView::RunCalculateRecursive(size_t index) {
545   while (index < m_CalculateNodes.size()) {
546     CXFA_Node* node = m_CalculateNodes[index];
547 
548     AddCalculateNodeNotify(node);
549     size_t recurse = node->JSObject()->GetCalcRecursionCount() + 1;
550     node->JSObject()->SetCalcRecursionCount(recurse);
551     if (recurse > 11)
552       break;
553     if (node->ProcessCalculate(this) == XFA_EventError::kSuccess &&
554         node->IsWidgetReady()) {
555       AddValidateNode(node);
556     }
557 
558     index = RunCalculateRecursive(++index);
559   }
560   return index;
561 }
562 
RunCalculateWidgets()563 XFA_EventError CXFA_FFDocView::RunCalculateWidgets() {
564   if (!m_pDoc->GetDocEnvironment()->IsCalculationsEnabled(m_pDoc.Get()))
565     return XFA_EventError::kDisabled;
566 
567   if (!m_CalculateNodes.empty())
568     RunCalculateRecursive(0);
569 
570   for (CXFA_Node* node : m_CalculateNodes)
571     node->JSObject()->SetCalcRecursionCount(0);
572 
573   m_CalculateNodes.clear();
574   return XFA_EventError::kSuccess;
575 }
576 
AddValidateNode(CXFA_Node * node)577 void CXFA_FFDocView::AddValidateNode(CXFA_Node* node) {
578   if (!pdfium::ContainsValue(m_ValidateNodes, node))
579     m_ValidateNodes.push_back(node);
580 }
581 
InitCalculate(CXFA_Node * pNode)582 void CXFA_FFDocView::InitCalculate(CXFA_Node* pNode) {
583   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_InitCalculate, false, true);
584 }
585 
ProcessValueChanged(CXFA_Node * node)586 void CXFA_FFDocView::ProcessValueChanged(CXFA_Node* node) {
587   AddValidateNode(node);
588   AddCalculateNode(node);
589   RunCalculateWidgets();
590   RunValidate();
591 }
592 
InitValidate(CXFA_Node * pNode)593 bool CXFA_FFDocView::InitValidate(CXFA_Node* pNode) {
594   if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
595     return false;
596 
597   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Validate, false, true);
598   m_ValidateNodes.clear();
599   return true;
600 }
601 
RunValidate()602 bool CXFA_FFDocView::RunValidate() {
603   if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
604     return false;
605 
606   while (!m_ValidateNodes.empty()) {
607     CXFA_Node* node = m_ValidateNodes.front();
608     m_ValidateNodes.pop_front();
609     if (!node->HasRemovedChildren())
610       node->ProcessValidate(this, 0);
611   }
612   return true;
613 }
614 
RunEventLayoutReady()615 bool CXFA_FFDocView::RunEventLayoutReady() {
616   CXFA_Node* pRootItem =
617       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
618   if (!pRootItem)
619     return false;
620 
621   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
622   RunLayout();
623   return true;
624 }
625 
RunBindItems()626 void CXFA_FFDocView::RunBindItems() {
627   while (!m_BindItems.empty()) {
628     CXFA_BindItems* item = m_BindItems.front();
629     m_BindItems.pop_front();
630     if (item->HasRemovedChildren())
631       continue;
632 
633     CXFA_Node* pWidgetNode = item->GetParent();
634     if (!pWidgetNode || !pWidgetNode->IsWidgetReady())
635       continue;
636 
637     CFXJSE_Engine* pScriptContext =
638         pWidgetNode->GetDocument()->GetScriptContext();
639     WideString wsRef = item->GetRef();
640     constexpr uint32_t kStyle =
641         XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
642         XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_ALL;
643     XFA_RESOLVENODE_RS rs;
644     pScriptContext->ResolveObjects(pWidgetNode, wsRef.AsStringView(), &rs,
645                                    kStyle, nullptr);
646     pWidgetNode->DeleteItem(-1, false, false);
647     if (rs.dwFlags != XFA_ResolveNode_RSType_Nodes || rs.objects.empty())
648       continue;
649 
650     WideString wsValueRef = item->GetValueRef();
651     WideString wsLabelRef = item->GetLabelRef();
652     const bool bUseValue = wsLabelRef.IsEmpty() || wsLabelRef == wsValueRef;
653     const bool bLabelUseContent =
654         wsLabelRef.IsEmpty() || wsLabelRef.EqualsASCII("$");
655     const bool bValueUseContent =
656         wsValueRef.IsEmpty() || wsValueRef.EqualsASCII("$");
657     WideString wsValue;
658     WideString wsLabel;
659     uint32_t uValueHash = FX_HashCode_GetW(wsValueRef.AsStringView(), false);
660     for (auto& refObject : rs.objects) {
661       CXFA_Node* refNode = refObject->AsNode();
662       if (!refNode)
663         continue;
664 
665       if (bValueUseContent) {
666         wsValue = refNode->JSObject()->GetContent(false);
667       } else {
668         CXFA_Node* nodeValue = refNode->GetFirstChildByName(uValueHash);
669         wsValue = nodeValue ? nodeValue->JSObject()->GetContent(false)
670                             : refNode->JSObject()->GetContent(false);
671       }
672 
673       if (!bUseValue) {
674         if (bLabelUseContent) {
675           wsLabel = refNode->JSObject()->GetContent(false);
676         } else {
677           CXFA_Node* nodeLabel =
678               refNode->GetFirstChildByName(wsLabelRef.AsStringView());
679           if (nodeLabel)
680             wsLabel = nodeLabel->JSObject()->GetContent(false);
681         }
682       } else {
683         wsLabel = wsValue;
684       }
685       pWidgetNode->InsertItem(wsLabel, wsValue, false);
686     }
687   }
688 }
689 
SetChangeMark()690 void CXFA_FFDocView::SetChangeMark() {
691   if (m_iStatus < XFA_DOCVIEW_LAYOUTSTATUS_End)
692     return;
693 
694   m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
695 }
696 
GetRootSubform()697 CXFA_Subform* CXFA_FFDocView::GetRootSubform() {
698   CXFA_Node* pFormPacketNode =
699       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
700   if (!pFormPacketNode)
701     return nullptr;
702 
703   return pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(
704       XFA_Element::Subform);
705 }
706