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