• 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/fx_extension.h"
13 #include "core/fxcrt/stl_util.h"
14 #include "core/fxcrt/xml/cfx_xmlparser.h"
15 #include "fxjs/gc/container_trace.h"
16 #include "fxjs/xfa/cfxjse_engine.h"
17 #include "fxjs/xfa/cjx_object.h"
18 #include "third_party/base/check_op.h"
19 #include "third_party/base/containers/contains.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 }  // namespace
61 
62 const XFA_AttributeValue kXFAEventActivity[] = {
63     XFA_AttributeValue::Click,      XFA_AttributeValue::Change,
64     XFA_AttributeValue::DocClose,   XFA_AttributeValue::DocReady,
65     XFA_AttributeValue::Enter,      XFA_AttributeValue::Exit,
66     XFA_AttributeValue::Full,       XFA_AttributeValue::IndexChange,
67     XFA_AttributeValue::Initialize, XFA_AttributeValue::MouseDown,
68     XFA_AttributeValue::MouseEnter, XFA_AttributeValue::MouseExit,
69     XFA_AttributeValue::MouseUp,    XFA_AttributeValue::PostExecute,
70     XFA_AttributeValue::PostOpen,   XFA_AttributeValue::PostPrint,
71     XFA_AttributeValue::PostSave,   XFA_AttributeValue::PostSign,
72     XFA_AttributeValue::PostSubmit, XFA_AttributeValue::PreExecute,
73     XFA_AttributeValue::PreOpen,    XFA_AttributeValue::PrePrint,
74     XFA_AttributeValue::PreSave,    XFA_AttributeValue::PreSign,
75     XFA_AttributeValue::PreSubmit,  XFA_AttributeValue::Ready,
76     XFA_AttributeValue::Unknown,
77 };
78 
UpdateScope(CXFA_FFDocView * pDocView)79 CXFA_FFDocView::UpdateScope::UpdateScope(CXFA_FFDocView* pDocView)
80     : m_pDocView(pDocView) {
81   m_pDocView->LockUpdate();
82 }
83 
~UpdateScope()84 CXFA_FFDocView::UpdateScope::~UpdateScope() {
85   m_pDocView->UnlockUpdate();
86   m_pDocView->UpdateDocView();
87 }
88 
CXFA_FFDocView(CXFA_FFDoc * pDoc)89 CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
90 
91 CXFA_FFDocView::~CXFA_FFDocView() = default;
92 
Trace(cppgc::Visitor * visitor) const93 void CXFA_FFDocView::Trace(cppgc::Visitor* visitor) const {
94   visitor->Trace(m_pDoc);
95   visitor->Trace(m_pWidgetHandler);
96   visitor->Trace(m_pFocusNode);
97   visitor->Trace(m_pFocusWidget);
98   ContainerTrace(visitor, m_ValidateNodes);
99   ContainerTrace(visitor, m_CalculateNodes);
100   ContainerTrace(visitor, m_NewAddedNodes);
101   ContainerTrace(visitor, m_BindItems);
102   ContainerTrace(visitor, m_IndexChangedSubforms);
103 }
104 
InitLayout(CXFA_Node * pNode)105 void CXFA_FFDocView::InitLayout(CXFA_Node* pNode) {
106   RunBindItems();
107   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Initialize, false, true);
108   ExecEventActivityByDeepFirst(pNode, XFA_EVENT_IndexChange, false, true);
109 }
110 
StartLayout()111 int32_t CXFA_FFDocView::StartLayout() {
112   m_iStatus = LayoutStatus::kStart;
113   m_pDoc->GetXFADoc()->DoProtoMerge();
114   m_pDoc->GetXFADoc()->DoDataMerge();
115 
116   int32_t iStatus = GetLayoutProcessor()->StartLayout();
117   if (iStatus < 0)
118     return iStatus;
119 
120   CXFA_Node* pRootItem =
121       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
122   if (!pRootItem)
123     return iStatus;
124 
125   InitLayout(pRootItem);
126   InitCalculate(pRootItem);
127   InitValidate(pRootItem);
128 
129   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, true, true);
130   m_iStatus = LayoutStatus::kStart;
131   return iStatus;
132 }
133 
DoLayout()134 int32_t CXFA_FFDocView::DoLayout() {
135   int32_t iStatus = GetLayoutProcessor()->DoLayout();
136   if (iStatus != 100)
137     return iStatus;
138 
139   m_iStatus = LayoutStatus::kDoing;
140   return iStatus;
141 }
142 
StopLayout()143 void CXFA_FFDocView::StopLayout() {
144   CXFA_Node* pRootItem =
145       ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
146   if (!pRootItem)
147     return;
148 
149   CXFA_Subform* pSubformNode =
150       pRootItem->GetChild<CXFA_Subform>(0, XFA_Element::Subform, false);
151   if (!pSubformNode)
152     return;
153 
154   CXFA_PageSet* pPageSetNode =
155       pSubformNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
156   if (!pPageSetNode)
157     return;
158 
159   RunCalculateWidgets();
160   RunValidate();
161 
162   InitLayout(pPageSetNode);
163   InitCalculate(pPageSetNode);
164   InitValidate(pPageSetNode);
165 
166   ExecEventActivityByDeepFirst(pPageSetNode, XFA_EVENT_Ready, true, true);
167   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
168   ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocReady, false, true);
169 
170   RunCalculateWidgets();
171   RunValidate();
172 
173   if (RunLayout())
174     ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
175 
176   m_CalculateNodes.clear();
177   if (m_pFocusNode && !m_pFocusWidget)
178     SetFocusNode(m_pFocusNode);
179 
180   m_iStatus = LayoutStatus::kEnd;
181 }
182 
AddNullTestMsg(const WideString & msg)183 void CXFA_FFDocView::AddNullTestMsg(const WideString& msg) {
184   m_NullTestMsgArray.push_back(msg);
185 }
186 
ShowNullTestMsg()187 void CXFA_FFDocView::ShowNullTestMsg() {
188   int32_t iCount = fxcrt::CollectionSize<int32_t>(m_NullTestMsgArray);
189   CXFA_FFApp* pApp = m_pDoc->GetApp();
190   CXFA_FFApp::CallbackIface* pAppProvider = pApp->GetAppProvider();
191   if (pAppProvider && iCount) {
192     int32_t iRemain = iCount > 7 ? iCount - 7 : 0;
193     iCount -= iRemain;
194     WideString wsMsg;
195     for (int32_t i = 0; i < iCount; i++)
196       wsMsg += m_NullTestMsgArray[i] + L"\n";
197 
198     if (iRemain > 0) {
199       wsMsg += L"\n" + WideString::Format(
200                            L"Message limit exceeded. Remaining %d "
201                            L"validation errors not reported.",
202                            iRemain);
203     }
204     pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(),
205                          static_cast<uint32_t>(AlertIcon::kStatus),
206                          static_cast<uint32_t>(AlertButton::kOK));
207   }
208   m_NullTestMsgArray.clear();
209 }
210 
UpdateDocView()211 void CXFA_FFDocView::UpdateDocView() {
212   if (IsUpdateLocked())
213     return;
214 
215   LockUpdate();
216   while (!m_NewAddedNodes.empty()) {
217     CXFA_Node* pNode = m_NewAddedNodes.front();
218     m_NewAddedNodes.pop_front();
219     InitCalculate(pNode);
220     InitValidate(pNode);
221     ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Ready, true, true);
222   }
223 
224   RunSubformIndexChange();
225   RunCalculateWidgets();
226   RunValidate();
227 
228   ShowNullTestMsg();
229 
230   if (RunLayout() && m_bLayoutEvent)
231     RunEventLayoutReady();
232 
233   m_bLayoutEvent = false;
234   m_CalculateNodes.clear();
235   UnlockUpdate();
236 }
237 
UpdateUIDisplay(CXFA_Node * pNode,CXFA_FFWidget * pExcept)238 void CXFA_FFDocView::UpdateUIDisplay(CXFA_Node* pNode, CXFA_FFWidget* pExcept) {
239   CXFA_FFWidget* pWidget = GetWidgetForNode(pNode);
240   CXFA_FFWidget* pNext = nullptr;
241   for (; pWidget; pWidget = pNext) {
242     pNext = pWidget->GetNextFFWidget();
243     if (pWidget == pExcept || !pWidget->IsLoaded() ||
244         (pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton &&
245          pWidget->IsFocused())) {
246       continue;
247     }
248     pWidget->UpdateFWLData();
249     pWidget->InvalidateRect();
250   }
251 }
252 
CountPageViews() const253 int32_t CXFA_FFDocView::CountPageViews() const {
254   CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
255   return pProcessor ? pProcessor->CountPages() : 0;
256 }
257 
GetPageView(int32_t nIndex) const258 CXFA_FFPageView* CXFA_FFDocView::GetPageView(int32_t nIndex) const {
259   CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
260   if (!pProcessor)
261     return nullptr;
262 
263   auto* pPage = pProcessor->GetPage(nIndex);
264   return pPage ? pPage->GetPageView() : nullptr;
265 }
266 
GetLayoutProcessor() const267 CXFA_LayoutProcessor* CXFA_FFDocView::GetLayoutProcessor() const {
268   return CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
269 }
270 
ResetSingleNodeData(CXFA_Node * pNode)271 bool CXFA_FFDocView::ResetSingleNodeData(CXFA_Node* pNode) {
272   XFA_Element eType = pNode->GetElementType();
273   if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
274     return false;
275 
276   pNode->ResetData();
277   UpdateUIDisplay(pNode, nullptr);
278   CXFA_Validate* validate = pNode->GetValidateIfExists();
279   if (!validate)
280     return true;
281 
282   AddValidateNode(pNode);
283   validate->SetFlag(XFA_NodeFlag::kNeedsInitApp);
284   return true;
285 }
286 
ResetNode(CXFA_Node * pNode)287 void CXFA_FFDocView::ResetNode(CXFA_Node* pNode) {
288   m_bLayoutEvent = true;
289   bool bChanged = false;
290   CXFA_Node* pFormNode = nullptr;
291   if (pNode) {
292     bChanged = ResetSingleNodeData(pNode);
293     pFormNode = pNode;
294   } else {
295     pFormNode = GetRootSubform();
296   }
297   if (!pFormNode)
298     return;
299 
300   if (pFormNode->GetElementType() != XFA_Element::Field &&
301       pFormNode->GetElementType() != XFA_Element::ExclGroup) {
302     CXFA_ReadyNodeIterator it(pFormNode);
303     while (CXFA_Node* next_node = it.MoveToNext()) {
304       bChanged |= ResetSingleNodeData(next_node);
305       if (next_node->GetElementType() == XFA_Element::ExclGroup)
306         it.SkipTree();
307     }
308   }
309   if (bChanged)
310     m_pDoc->SetChangeMark();
311 }
312 
GetWidgetForNode(CXFA_Node * node)313 CXFA_FFWidget* CXFA_FFDocView::GetWidgetForNode(CXFA_Node* node) {
314   return GetFFWidget(
315       ToContentLayoutItem(GetLayoutProcessor()->GetLayoutItem(node)));
316 }
317 
GetWidgetHandler()318 CXFA_FFWidgetHandler* CXFA_FFDocView::GetWidgetHandler() {
319   if (!m_pWidgetHandler) {
320     m_pWidgetHandler = cppgc::MakeGarbageCollected<CXFA_FFWidgetHandler>(
321         m_pDoc->GetHeap()->GetAllocationHandle(), this);
322   }
323   return m_pWidgetHandler;
324 }
325 
SetFocus(CXFA_FFWidget * pNewFocus)326 bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* pNewFocus) {
327   if (pNewFocus == m_pFocusWidget)
328     return false;
329 
330   if (m_pFocusWidget) {
331     CXFA_ContentLayoutItem* pItem = m_pFocusWidget->GetLayoutItem();
332     if (pItem->TestStatusBits(XFA_WidgetStatus::kVisible) &&
333         !pItem->TestStatusBits(XFA_WidgetStatus::kFocused)) {
334       if (!m_pFocusWidget->IsLoaded())
335         m_pFocusWidget->LoadWidget();
336       if (!m_pFocusWidget->OnSetFocus(m_pFocusWidget))
337         m_pFocusWidget.Clear();
338     }
339   }
340   if (m_pFocusWidget) {
341     if (!m_pFocusWidget->OnKillFocus(pNewFocus))
342       return false;
343   }
344 
345   if (pNewFocus) {
346     if (pNewFocus->GetLayoutItem()->TestStatusBits(
347             XFA_WidgetStatus::kVisible)) {
348       if (!pNewFocus->IsLoaded())
349         pNewFocus->LoadWidget();
350       if (!pNewFocus->OnSetFocus(m_pFocusWidget))
351         pNewFocus = nullptr;
352     }
353   }
354   if (pNewFocus) {
355     CXFA_Node* node = pNewFocus->GetNode();
356     m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
357     m_pFocusWidget = pNewFocus;
358   } else {
359     m_pFocusNode.Clear();
360     m_pFocusWidget.Clear();
361   }
362   return true;
363 }
364 
SetFocusNode(CXFA_Node * node)365 void CXFA_FFDocView::SetFocusNode(CXFA_Node* node) {
366   CXFA_FFWidget* pNewFocus = node ? GetWidgetForNode(node) : nullptr;
367   if (!SetFocus(pNewFocus))
368     return;
369 
370   m_pFocusNode = node;
371   if (m_iStatus != LayoutStatus::kEnd)
372     return;
373 
374   m_pDoc->SetFocusWidget(m_pFocusWidget);
375 }
376 
DeleteLayoutItem(CXFA_FFWidget * pWidget)377 void CXFA_FFDocView::DeleteLayoutItem(CXFA_FFWidget* pWidget) {
378   if (m_pFocusNode != pWidget->GetNode())
379     return;
380 
381   m_pFocusNode.Clear();
382   m_pFocusWidget.Clear();
383 }
384 
XFA_ProcessEvent(CXFA_FFDocView * pDocView,CXFA_Node * pNode,CXFA_EventParam * pParam)385 static XFA_EventError XFA_ProcessEvent(CXFA_FFDocView* pDocView,
386                                        CXFA_Node* pNode,
387                                        CXFA_EventParam* pParam) {
388   if (!pParam || pParam->m_eType == XFA_EVENT_Unknown)
389     return XFA_EventError::kNotExist;
390   if (pNode && pNode->GetElementType() == XFA_Element::Draw)
391     return XFA_EventError::kNotExist;
392 
393   switch (pParam->m_eType) {
394     case XFA_EVENT_Calculate:
395       return pNode->ProcessCalculate(pDocView);
396     case XFA_EVENT_Validate:
397       if (pDocView->GetDoc()->IsValidationsEnabled())
398         return pNode->ProcessValidate(pDocView, 0x01);
399       return XFA_EventError::kDisabled;
400     case XFA_EVENT_InitCalculate: {
401       CXFA_Calculate* calc = pNode->GetCalculateIfExists();
402       if (!calc)
403         return XFA_EventError::kNotExist;
404       if (pNode->IsUserInteractive())
405         return XFA_EventError::kDisabled;
406       return pNode->ExecuteScript(pDocView, calc->GetScriptIfExists(), pParam);
407     }
408     default:
409       return pNode->ProcessEvent(pDocView, kXFAEventActivity[pParam->m_eType],
410                                  pParam);
411   }
412 }
413 
ExecEventActivityByDeepFirst(CXFA_Node * pFormNode,XFA_EVENTTYPE eEventType,bool bIsFormReady,bool bRecursive)414 XFA_EventError CXFA_FFDocView::ExecEventActivityByDeepFirst(
415     CXFA_Node* pFormNode,
416     XFA_EVENTTYPE eEventType,
417     bool bIsFormReady,
418     bool bRecursive) {
419   if (!pFormNode)
420     return XFA_EventError::kNotExist;
421 
422   XFA_Element elementType = pFormNode->GetElementType();
423   if (elementType == XFA_Element::Field) {
424     if (eEventType == XFA_EVENT_IndexChange)
425       return XFA_EventError::kNotExist;
426 
427     if (!pFormNode->IsWidgetReady())
428       return XFA_EventError::kNotExist;
429 
430     CXFA_EventParam eParam;
431     eParam.m_eType = eEventType;
432     eParam.m_bIsFormReady = bIsFormReady;
433     return XFA_ProcessEvent(this, pFormNode, &eParam);
434   }
435 
436   XFA_EventError iRet = XFA_EventError::kNotExist;
437   if (bRecursive) {
438     for (CXFA_Node* pNode = pFormNode->GetFirstContainerChild(); pNode;
439          pNode = pNode->GetNextContainerSibling()) {
440       elementType = pNode->GetElementType();
441       if (elementType != XFA_Element::Variables &&
442           elementType != XFA_Element::Draw) {
443         XFA_EventErrorAccumulate(
444             &iRet, ExecEventActivityByDeepFirst(pNode, eEventType, bIsFormReady,
445                                                 bRecursive));
446       }
447     }
448   }
449   if (!pFormNode->IsWidgetReady())
450     return iRet;
451 
452   CXFA_EventParam eParam;
453   eParam.m_eType = eEventType;
454   eParam.m_bIsFormReady = bIsFormReady;
455 
456   XFA_EventErrorAccumulate(&iRet, XFA_ProcessEvent(this, pFormNode, &eParam));
457   return iRet;
458 }
459 
GetWidgetByName(const WideString & wsName,CXFA_FFWidget * pRefWidget)460 CXFA_FFWidget* CXFA_FFDocView::GetWidgetByName(const WideString& wsName,
461                                                CXFA_FFWidget* pRefWidget) {
462   if (!IsValidXMLNameString(wsName)) {
463     return nullptr;
464   }
465   CFXJSE_Engine* pScriptContext = m_pDoc->GetXFADoc()->GetScriptContext();
466   CXFA_Node* pRefNode = nullptr;
467   if (pRefWidget) {
468     CXFA_Node* node = pRefWidget->GetNode();
469     pRefNode = node->IsWidgetReady() ? node : nullptr;
470   }
471   WideString wsExpression = (!pRefNode ? L"$form." : L"") + wsName;
472   absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
473       pScriptContext->ResolveObjects(
474           pRefNode, wsExpression.AsStringView(),
475           Mask<XFA_ResolveFlag>{
476               XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kProperties,
477               XFA_ResolveFlag::kSiblings, XFA_ResolveFlag::kParent});
478   if (!maybeResult.has_value())
479     return nullptr;
480 
481   if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
482     CXFA_Node* pNode = maybeResult.value().objects.front()->AsNode();
483     if (pNode && pNode->IsWidgetReady())
484       return GetWidgetForNode(pNode);
485   }
486   return nullptr;
487 }
488 
OnPageViewEvent(CXFA_ViewLayoutItem * pSender,CXFA_FFDoc::PageViewEvent eEvent)489 void CXFA_FFDocView::OnPageViewEvent(CXFA_ViewLayoutItem* pSender,
490                                      CXFA_FFDoc::PageViewEvent eEvent) {
491   CXFA_FFPageView* pFFPageView = pSender ? pSender->GetPageView() : nullptr;
492   m_pDoc->OnPageViewEvent(pFFPageView, eEvent);
493 }
494 
InvalidateRect(CXFA_FFPageView * pPageView,const CFX_RectF & rtInvalidate)495 void CXFA_FFDocView::InvalidateRect(CXFA_FFPageView* pPageView,
496                                     const CFX_RectF& rtInvalidate) {
497   m_pDoc->InvalidateRect(pPageView, rtInvalidate);
498 }
499 
RunLayout()500 bool CXFA_FFDocView::RunLayout() {
501   LockUpdate();
502   m_bInLayoutStatus = true;
503 
504   CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
505   if (!pProcessor->IncrementLayout() && pProcessor->StartLayout() < 100) {
506     pProcessor->DoLayout();
507     UnlockUpdate();
508     m_bInLayoutStatus = false;
509     m_pDoc->OnPageViewEvent(nullptr, CXFA_FFDoc::PageViewEvent::kStopLayout);
510     return true;
511   }
512 
513   m_bInLayoutStatus = false;
514   m_pDoc->OnPageViewEvent(nullptr, CXFA_FFDoc::PageViewEvent::kStopLayout);
515   UnlockUpdate();
516   return false;
517 }
518 
RunSubformIndexChange()519 void CXFA_FFDocView::RunSubformIndexChange() {
520   std::set<CXFA_Node*> seen;
521   while (!m_IndexChangedSubforms.empty()) {
522     CXFA_Node* pSubformNode = m_IndexChangedSubforms.front();
523     m_IndexChangedSubforms.pop_front();
524     bool bInserted = seen.insert(pSubformNode).second;
525     if (!bInserted || !pSubformNode->IsWidgetReady())
526       continue;
527 
528     CXFA_EventParam eParam;
529     eParam.m_eType = 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     absl::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