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