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