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