1// Copyright 2016 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/parser/cxfa_node.h"
8
9#include <map>
10#include <memory>
11#include <set>
12#include <utility>
13#include <vector>
14
15#include "core/fxcrt/autorestorer.h"
16#include "core/fxcrt/cfx_decimal.h"
17#include "core/fxcrt/cfx_memorystream.h"
18#include "core/fxcrt/fx_codepage.h"
19#include "core/fxcrt/fx_extension.h"
20#include "core/fxcrt/xml/cfx_xmlelement.h"
21#include "core/fxcrt/xml/cfx_xmlnode.h"
22#include "core/fxcrt/xml/cfx_xmltext.h"
23#include "fxjs/cfxjse_engine.h"
24#include "fxjs/cfxjse_value.h"
25#include "fxjs/xfa/cjx_node.h"
26#include "third_party/base/logging.h"
27#include "third_party/base/ptr_util.h"
28#include "third_party/base/stl_util.h"
29#include "xfa/fxfa/cxfa_eventparam.h"
30#include "xfa/fxfa/cxfa_ffapp.h"
31#include "xfa/fxfa/cxfa_ffdocview.h"
32#include "xfa/fxfa/cxfa_ffnotify.h"
33#include "xfa/fxfa/cxfa_ffwidget.h"
34#include "xfa/fxfa/parser/cxfa_arraynodelist.h"
35#include "xfa/fxfa/parser/cxfa_attachnodelist.h"
36#include "xfa/fxfa/parser/cxfa_bind.h"
37#include "xfa/fxfa/parser/cxfa_border.h"
38#include "xfa/fxfa/parser/cxfa_calculate.h"
39#include "xfa/fxfa/parser/cxfa_caption.h"
40#include "xfa/fxfa/parser/cxfa_document.h"
41#include "xfa/fxfa/parser/cxfa_event.h"
42#include "xfa/fxfa/parser/cxfa_font.h"
43#include "xfa/fxfa/parser/cxfa_keep.h"
44#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
45#include "xfa/fxfa/parser/cxfa_localevalue.h"
46#include "xfa/fxfa/parser/cxfa_margin.h"
47#include "xfa/fxfa/parser/cxfa_measurement.h"
48#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
49#include "xfa/fxfa/parser/cxfa_occur.h"
50#include "xfa/fxfa/parser/cxfa_para.h"
51#include "xfa/fxfa/parser/cxfa_simple_parser.h"
52#include "xfa/fxfa/parser/cxfa_subform.h"
53#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
54#include "xfa/fxfa/parser/cxfa_validate.h"
55#include "xfa/fxfa/parser/cxfa_value.h"
56#include "xfa/fxfa/parser/xfa_basic_data.h"
57#include "xfa/fxfa/parser/xfa_utils.h"
58
59namespace {
60
61constexpr uint8_t kMaxExecuteRecursion = 2;
62
63std::vector<CXFA_Node*> NodesSortedByDocumentIdx(
64    const std::set<CXFA_Node*>& rgNodeSet) {
65  if (rgNodeSet.empty())
66    return std::vector<CXFA_Node*>();
67
68  std::vector<CXFA_Node*> rgNodeArray;
69  CXFA_Node* pCommonParent = (*rgNodeSet.begin())->GetParent();
70  for (CXFA_Node* pNode = pCommonParent->GetFirstChild(); pNode;
71       pNode = pNode->GetNextSibling()) {
72    if (pdfium::ContainsValue(rgNodeSet, pNode))
73      rgNodeArray.push_back(pNode);
74  }
75  return rgNodeArray;
76}
77
78using CXFA_NodeSetPair = std::pair<std::set<CXFA_Node*>, std::set<CXFA_Node*>>;
79using CXFA_NodeSetPairMap =
80    std::map<uint32_t, std::unique_ptr<CXFA_NodeSetPair>>;
81using CXFA_NodeSetPairMapMap =
82    std::map<CXFA_Node*, std::unique_ptr<CXFA_NodeSetPairMap>>;
83
84CXFA_NodeSetPair* NodeSetPairForNode(CXFA_Node* pNode,
85                                     CXFA_NodeSetPairMapMap* pMap) {
86  CXFA_Node* pParentNode = pNode->GetParent();
87  uint32_t dwNameHash = pNode->GetNameHash();
88  if (!pParentNode || !dwNameHash)
89    return nullptr;
90
91  if (!(*pMap)[pParentNode])
92    (*pMap)[pParentNode] = pdfium::MakeUnique<CXFA_NodeSetPairMap>();
93
94  CXFA_NodeSetPairMap* pNodeSetPairMap = (*pMap)[pParentNode].get();
95  if (!(*pNodeSetPairMap)[dwNameHash])
96    (*pNodeSetPairMap)[dwNameHash] = pdfium::MakeUnique<CXFA_NodeSetPair>();
97
98  return (*pNodeSetPairMap)[dwNameHash].get();
99}
100
101void ReorderDataNodes(const std::set<CXFA_Node*>& sSet1,
102                      const std::set<CXFA_Node*>& sSet2,
103                      bool bInsertBefore) {
104  CXFA_NodeSetPairMapMap rgMap;
105  for (CXFA_Node* pNode : sSet1) {
106    CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
107    if (pNodeSetPair)
108      pNodeSetPair->first.insert(pNode);
109  }
110  for (CXFA_Node* pNode : sSet2) {
111    CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
112    if (pNodeSetPair) {
113      if (pdfium::ContainsValue(pNodeSetPair->first, pNode))
114        pNodeSetPair->first.erase(pNode);
115      else
116        pNodeSetPair->second.insert(pNode);
117    }
118  }
119  for (const auto& iter1 : rgMap) {
120    CXFA_NodeSetPairMap* pNodeSetPairMap = iter1.second.get();
121    if (!pNodeSetPairMap)
122      continue;
123
124    for (const auto& iter2 : *pNodeSetPairMap) {
125      CXFA_NodeSetPair* pNodeSetPair = iter2.second.get();
126      if (!pNodeSetPair)
127        continue;
128      if (!pNodeSetPair->first.empty() && !pNodeSetPair->second.empty()) {
129        std::vector<CXFA_Node*> rgNodeArray1 =
130            NodesSortedByDocumentIdx(pNodeSetPair->first);
131        std::vector<CXFA_Node*> rgNodeArray2 =
132            NodesSortedByDocumentIdx(pNodeSetPair->second);
133        CXFA_Node* pParentNode = nullptr;
134        CXFA_Node* pBeforeNode = nullptr;
135        if (bInsertBefore) {
136          pBeforeNode = rgNodeArray2.front();
137          pParentNode = pBeforeNode->GetParent();
138        } else {
139          CXFA_Node* pLastNode = rgNodeArray2.back();
140          pParentNode = pLastNode->GetParent();
141          pBeforeNode = pLastNode->GetNextSibling();
142        }
143        for (auto* pCurNode : rgNodeArray1) {
144          pParentNode->RemoveChild(pCurNode, true);
145          pParentNode->InsertChild(pCurNode, pBeforeNode);
146        }
147      }
148    }
149    pNodeSetPairMap->clear();
150  }
151}
152
153}  // namespace
154
155// static
156WideString CXFA_Node::AttributeEnumToName(XFA_AttributeEnum item) {
157  return g_XFAEnumData[static_cast<int32_t>(item)].pName;
158}
159
160// static
161Optional<XFA_AttributeEnum> CXFA_Node::NameToAttributeEnum(
162    const WideStringView& name) {
163  if (name.IsEmpty())
164    return {};
165
166  auto* it = std::lower_bound(g_XFAEnumData, g_XFAEnumData + g_iXFAEnumCount,
167                              FX_HashCode_GetW(name, false),
168                              [](const XFA_AttributeEnumInfo& arg,
169                                 uint32_t hash) { return arg.uHash < hash; });
170  if (it != g_XFAEnumData + g_iXFAEnumCount && name == it->pName)
171    return {it->eName};
172  return {};
173}
174
175CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
176                     XFA_PacketType ePacket,
177                     uint32_t validPackets,
178                     XFA_ObjectType oType,
179                     XFA_Element eType,
180                     const PropertyData* properties,
181                     const AttributeData* attributes,
182                     const WideStringView& elementName,
183                     std::unique_ptr<CJX_Object> js_node)
184    : CXFA_Object(pDoc, oType, eType, elementName, std::move(js_node)),
185      m_Properties(properties),
186      m_Attributes(attributes),
187      m_ValidPackets(validPackets),
188      m_pNext(nullptr),
189      m_pChild(nullptr),
190      m_pLastChild(nullptr),
191      m_pParent(nullptr),
192      m_pXMLNode(nullptr),
193      m_ePacket(ePacket),
194      m_uNodeFlags(XFA_NodeFlag_None),
195      m_dwNameHash(0),
196      m_pAuxNode(nullptr) {
197  ASSERT(m_pDocument);
198}
199
200CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
201                     XFA_PacketType ePacket,
202                     uint32_t validPackets,
203                     XFA_ObjectType oType,
204                     XFA_Element eType,
205                     const PropertyData* properties,
206                     const AttributeData* attributes,
207                     const WideStringView& elementName)
208    : CXFA_Node(pDoc,
209                ePacket,
210                validPackets,
211                oType,
212                eType,
213                properties,
214                attributes,
215                elementName,
216                pdfium::MakeUnique<CJX_Node>(this)) {}
217
218CXFA_Node::~CXFA_Node() {
219  ASSERT(!m_pParent);
220
221  CXFA_Node* pNode = m_pChild;
222  while (pNode) {
223    CXFA_Node* pNext = pNode->m_pNext;
224    pNode->m_pParent = nullptr;
225    delete pNode;
226    pNode = pNext;
227  }
228  if (m_pXMLNode && IsOwnXMLNode())
229    delete m_pXMLNode;
230}
231
232CXFA_Node* CXFA_Node::Clone(bool bRecursive) {
233  CXFA_Node* pClone = m_pDocument->CreateNode(m_ePacket, m_elementType);
234  if (!pClone)
235    return nullptr;
236
237  JSObject()->MergeAllData(pClone);
238  pClone->UpdateNameHash();
239  if (IsNeedSavingXMLNode()) {
240    std::unique_ptr<CFX_XMLNode> pCloneXML;
241    if (IsAttributeInXML()) {
242      WideString wsName = JSObject()
243                              ->TryAttribute(XFA_Attribute::Name, false)
244                              .value_or(WideString());
245      auto pCloneXMLElement = pdfium::MakeUnique<CFX_XMLElement>(wsName);
246      WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
247      if (!wsValue.IsEmpty())
248        pCloneXMLElement->SetTextData(WideString(wsValue));
249
250      pCloneXML.reset(pCloneXMLElement.release());
251      pClone->JSObject()->SetEnum(XFA_Attribute::Contains,
252                                  XFA_AttributeEnum::Unknown, false);
253    } else {
254      pCloneXML = m_pXMLNode->Clone();
255    }
256    pClone->SetXMLMappingNode(pCloneXML.release());
257    pClone->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
258  }
259  if (bRecursive) {
260    for (CXFA_Node* pChild = GetFirstChild(); pChild;
261         pChild = pChild->GetNextSibling()) {
262      pClone->InsertChild(pChild->Clone(bRecursive), nullptr);
263    }
264  }
265  pClone->SetFlag(XFA_NodeFlag_Initialized, true);
266  pClone->SetBindingNode(nullptr);
267  return pClone;
268}
269
270CXFA_Node* CXFA_Node::GetPrevSibling() const {
271  if (!m_pParent || m_pParent->m_pChild == this)
272    return nullptr;
273
274  for (CXFA_Node* pNode = m_pParent->m_pChild; pNode; pNode = pNode->m_pNext) {
275    if (pNode->m_pNext == this)
276      return pNode;
277  }
278  return nullptr;
279}
280
281CXFA_Node* CXFA_Node::GetNextContainerSibling() const {
282  CXFA_Node* pNode = m_pNext;
283  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
284    pNode = pNode->m_pNext;
285  return pNode;
286}
287
288CXFA_Node* CXFA_Node::GetPrevContainerSibling() const {
289  if (!m_pParent || m_pParent->m_pChild == this)
290    return nullptr;
291
292  CXFA_Node* container = nullptr;
293  for (CXFA_Node* pNode = m_pParent->m_pChild; pNode; pNode = pNode->m_pNext) {
294    if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
295      container = pNode;
296    if (pNode->m_pNext == this)
297      return container;
298  }
299  return nullptr;
300}
301
302CXFA_Node* CXFA_Node::GetFirstContainerChild() const {
303  CXFA_Node* pNode = m_pChild;
304  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
305    pNode = pNode->m_pNext;
306  return pNode;
307}
308
309CXFA_Node* CXFA_Node::GetContainerParent() const {
310  CXFA_Node* pNode = m_pParent;
311  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
312    pNode = pNode->m_pParent;
313  return pNode;
314}
315
316bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const {
317  return !!(m_ValidPackets & (1 << static_cast<uint8_t>(packet)));
318}
319
320const CXFA_Node::PropertyData* CXFA_Node::GetPropertyData(
321    XFA_Element property) const {
322  if (m_Properties == nullptr)
323    return nullptr;
324
325  for (size_t i = 0;; ++i) {
326    const PropertyData* data = m_Properties + i;
327    if (data->property == XFA_Element::Unknown)
328      break;
329    if (data->property == property)
330      return data;
331  }
332  return nullptr;
333}
334
335bool CXFA_Node::HasProperty(XFA_Element property) const {
336  return !!GetPropertyData(property);
337}
338
339bool CXFA_Node::HasPropertyFlags(XFA_Element property, uint8_t flags) const {
340  const PropertyData* data = GetPropertyData(property);
341  return data && !!(data->flags & flags);
342}
343
344uint8_t CXFA_Node::PropertyOccuranceCount(XFA_Element property) const {
345  const PropertyData* data = GetPropertyData(property);
346  return data ? data->occurance_count : 0;
347}
348
349Optional<XFA_Element> CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) {
350  if (m_Properties == nullptr)
351    return {};
352
353  for (size_t i = 0;; ++i) {
354    const PropertyData* data = m_Properties + i;
355    if (data->property == XFA_Element::Unknown)
356      break;
357    if (data->flags & flag)
358      return {data->property};
359  }
360  return {};
361}
362
363const CXFA_Node::AttributeData* CXFA_Node::GetAttributeData(
364    XFA_Attribute attr) const {
365  if (m_Attributes == nullptr)
366    return nullptr;
367
368  for (size_t i = 0;; ++i) {
369    const AttributeData* cur_attr = &m_Attributes[i];
370    if (cur_attr->attribute == XFA_Attribute::Unknown)
371      break;
372    if (cur_attr->attribute == attr)
373      return cur_attr;
374  }
375  return nullptr;
376}
377
378bool CXFA_Node::HasAttribute(XFA_Attribute attr) const {
379  return !!GetAttributeData(attr);
380}
381
382// Note: This Method assumes that i is a valid index ....
383XFA_Attribute CXFA_Node::GetAttribute(size_t i) const {
384  if (m_Attributes == nullptr)
385    return XFA_Attribute::Unknown;
386  return m_Attributes[i].attribute;
387}
388
389XFA_AttributeType CXFA_Node::GetAttributeType(XFA_Attribute type) const {
390  const AttributeData* data = GetAttributeData(type);
391  return data ? data->type : XFA_AttributeType::CData;
392}
393
394std::vector<CXFA_Node*> CXFA_Node::GetNodeList(uint32_t dwTypeFilter,
395                                               XFA_Element eTypeFilter) {
396  if (eTypeFilter != XFA_Element::Unknown) {
397    std::vector<CXFA_Node*> nodes;
398    for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) {
399      if (pChild->GetElementType() == eTypeFilter)
400        nodes.push_back(pChild);
401    }
402    return nodes;
403  }
404
405  if (dwTypeFilter == (XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties)) {
406    std::vector<CXFA_Node*> nodes;
407    for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext)
408      nodes.push_back(pChild);
409    return nodes;
410  }
411
412  if (dwTypeFilter == 0)
413    return std::vector<CXFA_Node*>();
414
415  bool bFilterChildren = !!(dwTypeFilter & XFA_NODEFILTER_Children);
416  bool bFilterProperties = !!(dwTypeFilter & XFA_NODEFILTER_Properties);
417  bool bFilterOneOfProperties = !!(dwTypeFilter & XFA_NODEFILTER_OneOfProperty);
418  std::vector<CXFA_Node*> nodes;
419  for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) {
420    if (!HasProperty(pChild->GetElementType())) {
421      if (bFilterProperties) {
422        nodes.push_back(pChild);
423      } else if (bFilterOneOfProperties &&
424                 HasPropertyFlags(pChild->GetElementType(),
425                                  XFA_PROPERTYFLAG_OneOf)) {
426        nodes.push_back(pChild);
427      } else if (bFilterChildren &&
428                 (pChild->GetElementType() == XFA_Element::Variables ||
429                  pChild->GetElementType() == XFA_Element::PageSet)) {
430        nodes.push_back(pChild);
431      }
432    } else if (bFilterChildren) {
433      nodes.push_back(pChild);
434    }
435  }
436
437  if (!bFilterOneOfProperties || !nodes.empty())
438    return nodes;
439  if (m_Properties == nullptr)
440    return nodes;
441
442  Optional<XFA_Element> property =
443      GetFirstPropertyWithFlag(XFA_PROPERTYFLAG_DefaultOneOf);
444  if (!property)
445    return nodes;
446
447  CXFA_Node* pNewNode = m_pDocument->CreateNode(GetPacketType(), *property);
448  if (pNewNode) {
449    InsertChild(pNewNode, nullptr);
450    pNewNode->SetFlag(XFA_NodeFlag_Initialized, true);
451    nodes.push_back(pNewNode);
452  }
453  return nodes;
454}
455
456CXFA_Node* CXFA_Node::CreateSamePacketNode(XFA_Element eType) {
457  CXFA_Node* pNode = m_pDocument->CreateNode(m_ePacket, eType);
458  pNode->SetFlag(XFA_NodeFlag_Initialized, true);
459  return pNode;
460}
461
462CXFA_Node* CXFA_Node::CloneTemplateToForm(bool bRecursive) {
463  ASSERT(m_ePacket == XFA_PacketType::Template);
464  CXFA_Node* pClone =
465      m_pDocument->CreateNode(XFA_PacketType::Form, m_elementType);
466  if (!pClone)
467    return nullptr;
468
469  pClone->SetTemplateNode(this);
470  pClone->UpdateNameHash();
471  pClone->SetXMLMappingNode(GetXMLMappingNode());
472  if (bRecursive) {
473    for (CXFA_Node* pChild = GetFirstChild(); pChild;
474         pChild = pChild->GetNextSibling()) {
475      pClone->InsertChild(pChild->CloneTemplateToForm(bRecursive), nullptr);
476    }
477  }
478  pClone->SetFlag(XFA_NodeFlag_Initialized, true);
479  return pClone;
480}
481
482CXFA_Node* CXFA_Node::GetTemplateNodeIfExists() const {
483  return m_pAuxNode;
484}
485
486void CXFA_Node::SetTemplateNode(CXFA_Node* pTemplateNode) {
487  m_pAuxNode = pTemplateNode;
488}
489
490CXFA_Node* CXFA_Node::GetBindData() {
491  ASSERT(GetPacketType() == XFA_PacketType::Form);
492  return GetBindingNode();
493}
494
495std::vector<UnownedPtr<CXFA_Node>>* CXFA_Node::GetBindItems() {
496  return GetBindingNodes();
497}
498
499int32_t CXFA_Node::AddBindItem(CXFA_Node* pFormNode) {
500  ASSERT(pFormNode);
501
502  if (BindsFormItems()) {
503    bool found = false;
504    for (auto& v : binding_nodes_) {
505      if (v.Get() == pFormNode) {
506        found = true;
507        break;
508      }
509    }
510    if (!found)
511      binding_nodes_.emplace_back(pFormNode);
512    return pdfium::CollectionSize<int32_t>(binding_nodes_);
513  }
514
515  CXFA_Node* pOldFormItem = GetBindingNode();
516  if (!pOldFormItem) {
517    SetBindingNode(pFormNode);
518    return 1;
519  }
520  if (pOldFormItem == pFormNode)
521    return 1;
522
523  std::vector<UnownedPtr<CXFA_Node>> items;
524  items.emplace_back(pOldFormItem);
525  items.emplace_back(pFormNode);
526  SetBindingNodes(std::move(items));
527
528  m_uNodeFlags |= XFA_NodeFlag_BindFormItems;
529  return 2;
530}
531
532int32_t CXFA_Node::RemoveBindItem(CXFA_Node* pFormNode) {
533  if (BindsFormItems()) {
534    auto it = std::find_if(binding_nodes_.begin(), binding_nodes_.end(),
535                           [&pFormNode](const UnownedPtr<CXFA_Node>& node) {
536                             return node.Get() == pFormNode;
537                           });
538    if (it != binding_nodes_.end())
539      binding_nodes_.erase(it);
540
541    if (binding_nodes_.size() == 1) {
542      m_uNodeFlags &= ~XFA_NodeFlag_BindFormItems;
543      return 1;
544    }
545    return pdfium::CollectionSize<int32_t>(binding_nodes_);
546  }
547
548  CXFA_Node* pOldFormItem = GetBindingNode();
549  if (pOldFormItem != pFormNode)
550    return pOldFormItem ? 1 : 0;
551
552  SetBindingNode(nullptr);
553  return 0;
554}
555
556bool CXFA_Node::HasBindItem() {
557  return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode();
558}
559
560CXFA_WidgetAcc* CXFA_Node::GetContainerWidgetAcc() {
561  if (GetPacketType() != XFA_PacketType::Form)
562    return nullptr;
563  XFA_Element eType = GetElementType();
564  if (eType == XFA_Element::ExclGroup)
565    return nullptr;
566  CXFA_Node* pParentNode = GetParent();
567  if (pParentNode && pParentNode->GetElementType() == XFA_Element::ExclGroup)
568    return nullptr;
569
570  if (eType == XFA_Element::Field) {
571    CXFA_WidgetAcc* pFieldWidgetAcc = GetWidgetAcc();
572    if (pFieldWidgetAcc && pFieldWidgetAcc->IsChoiceListMultiSelect())
573      return nullptr;
574
575    WideString wsPicture;
576    if (pFieldWidgetAcc) {
577      wsPicture = pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind);
578    }
579    if (!wsPicture.IsEmpty())
580      return pFieldWidgetAcc;
581
582    CXFA_Node* pDataNode = GetBindData();
583    if (!pDataNode)
584      return nullptr;
585    pFieldWidgetAcc = nullptr;
586    for (const auto& pFormNode : *(pDataNode->GetBindItems())) {
587      if (!pFormNode || pFormNode->HasRemovedChildren())
588        continue;
589      pFieldWidgetAcc = pFormNode->GetWidgetAcc();
590      if (pFieldWidgetAcc) {
591        wsPicture =
592            pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind);
593      }
594      if (!wsPicture.IsEmpty())
595        break;
596      pFieldWidgetAcc = nullptr;
597    }
598    return pFieldWidgetAcc;
599  }
600
601  CXFA_Node* pGrandNode = pParentNode ? pParentNode->GetParent() : nullptr;
602  CXFA_Node* pValueNode =
603      (pParentNode && pParentNode->GetElementType() == XFA_Element::Value)
604          ? pParentNode
605          : nullptr;
606  if (!pValueNode) {
607    pValueNode =
608        (pGrandNode && pGrandNode->GetElementType() == XFA_Element::Value)
609            ? pGrandNode
610            : nullptr;
611  }
612  CXFA_Node* pParentOfValueNode =
613      pValueNode ? pValueNode->GetParent() : nullptr;
614  return pParentOfValueNode ? pParentOfValueNode->GetContainerWidgetAcc()
615                            : nullptr;
616}
617
618IFX_Locale* CXFA_Node::GetLocale() {
619  Optional<WideString> localeName = GetLocaleName();
620  if (!localeName)
621    return nullptr;
622  if (localeName.value() == L"ambient")
623    return GetDocument()->GetLocalMgr()->GetDefLocale();
624  return GetDocument()->GetLocalMgr()->GetLocaleByName(localeName.value());
625}
626
627Optional<WideString> CXFA_Node::GetLocaleName() {
628  CXFA_Node* pForm = GetDocument()->GetXFAObject(XFA_HASHCODE_Form)->AsNode();
629  CXFA_Subform* pTopSubform =
630      pForm->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
631  ASSERT(pTopSubform);
632
633  CXFA_Node* pLocaleNode = this;
634  do {
635    Optional<WideString> localeName =
636        pLocaleNode->JSObject()->TryCData(XFA_Attribute::Locale, false);
637    if (localeName)
638      return localeName;
639
640    pLocaleNode = pLocaleNode->GetParent();
641  } while (pLocaleNode && pLocaleNode != pTopSubform);
642
643  CXFA_Node* pConfig = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
644  Optional<WideString> localeName = {
645      WideString(GetDocument()->GetLocalMgr()->GetConfigLocaleName(pConfig))};
646  if (localeName && !localeName->IsEmpty())
647    return localeName;
648
649  if (pTopSubform) {
650    localeName =
651        pTopSubform->JSObject()->TryCData(XFA_Attribute::Locale, false);
652    if (localeName)
653      return localeName;
654  }
655
656  IFX_Locale* pLocale = GetDocument()->GetLocalMgr()->GetDefLocale();
657  if (!pLocale)
658    return {};
659
660  return {pLocale->GetName()};
661}
662
663XFA_AttributeEnum CXFA_Node::GetIntact() {
664  CXFA_Keep* pKeep = GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
665  XFA_AttributeEnum eLayoutType = JSObject()
666                                      ->TryEnum(XFA_Attribute::Layout, true)
667                                      .value_or(XFA_AttributeEnum::Position);
668  if (pKeep) {
669    Optional<XFA_AttributeEnum> intact =
670        pKeep->JSObject()->TryEnum(XFA_Attribute::Intact, false);
671    if (intact) {
672      if (*intact == XFA_AttributeEnum::None &&
673          eLayoutType == XFA_AttributeEnum::Row &&
674          m_pDocument->GetCurVersionMode() < XFA_VERSION_208) {
675        CXFA_Node* pPreviewRow = GetPrevContainerSibling();
676        if (pPreviewRow &&
677            pPreviewRow->JSObject()->GetEnum(XFA_Attribute::Layout) ==
678                XFA_AttributeEnum::Row) {
679          Optional<XFA_AttributeEnum> value =
680              pKeep->JSObject()->TryEnum(XFA_Attribute::Previous, false);
681          if (value && (*value == XFA_AttributeEnum::ContentArea ||
682                        *value == XFA_AttributeEnum::PageArea)) {
683            return XFA_AttributeEnum::ContentArea;
684          }
685
686          CXFA_Keep* pNode =
687              pPreviewRow->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
688          Optional<XFA_AttributeEnum> ret;
689          if (pNode)
690            ret = pNode->JSObject()->TryEnum(XFA_Attribute::Next, false);
691          if (ret && (*ret == XFA_AttributeEnum::ContentArea ||
692                      *ret == XFA_AttributeEnum::PageArea)) {
693            return XFA_AttributeEnum::ContentArea;
694          }
695        }
696      }
697      return *intact;
698    }
699  }
700
701  switch (GetElementType()) {
702    case XFA_Element::Subform:
703      switch (eLayoutType) {
704        case XFA_AttributeEnum::Position:
705        case XFA_AttributeEnum::Row:
706          return XFA_AttributeEnum::ContentArea;
707        default:
708          return XFA_AttributeEnum::None;
709      }
710    case XFA_Element::Field: {
711      CXFA_Node* parent = GetParent();
712      if (!parent || parent->GetElementType() == XFA_Element::PageArea)
713        return XFA_AttributeEnum::ContentArea;
714      if (parent->GetIntact() != XFA_AttributeEnum::None)
715        return XFA_AttributeEnum::ContentArea;
716
717      XFA_AttributeEnum eParLayout = parent->JSObject()
718                                         ->TryEnum(XFA_Attribute::Layout, true)
719                                         .value_or(XFA_AttributeEnum::Position);
720      if (eParLayout == XFA_AttributeEnum::Position ||
721          eParLayout == XFA_AttributeEnum::Row ||
722          eParLayout == XFA_AttributeEnum::Table) {
723        return XFA_AttributeEnum::None;
724      }
725
726      XFA_VERSION version = m_pDocument->GetCurVersionMode();
727      if (eParLayout == XFA_AttributeEnum::Tb && version < XFA_VERSION_208) {
728        Optional<CXFA_Measurement> measureH =
729            JSObject()->TryMeasure(XFA_Attribute::H, false);
730        if (measureH)
731          return XFA_AttributeEnum::ContentArea;
732      }
733      return XFA_AttributeEnum::None;
734    }
735    case XFA_Element::Draw:
736      return XFA_AttributeEnum::ContentArea;
737    default:
738      return XFA_AttributeEnum::None;
739  }
740}
741
742CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
743  if (m_ePacket == XFA_PacketType::Datasets)
744    return m_pAuxNode;
745  return nullptr;
746}
747
748void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) {
749  ASSERT(m_ePacket == XFA_PacketType::Datasets);
750  m_pAuxNode = pDataDescriptionNode;
751}
752
753CXFA_Node* CXFA_Node::GetModelNode() {
754  switch (GetPacketType()) {
755    case XFA_PacketType::Xdp:
756      return m_pDocument->GetRoot();
757    case XFA_PacketType::Config:
758      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config));
759    case XFA_PacketType::Template:
760      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Template));
761    case XFA_PacketType::Form:
762      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
763    case XFA_PacketType::Datasets:
764      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Datasets));
765    case XFA_PacketType::LocaleSet:
766      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_LocaleSet));
767    case XFA_PacketType::ConnectionSet:
768      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_ConnectionSet));
769    case XFA_PacketType::SourceSet:
770      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_SourceSet));
771    case XFA_PacketType::Xdc:
772      return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Xdc));
773    default:
774      return this;
775  }
776}
777
778size_t CXFA_Node::CountChildren(XFA_Element eType, bool bOnlyChild) {
779  size_t count = 0;
780  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNextSibling()) {
781    if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
782      continue;
783    if (bOnlyChild && HasProperty(pNode->GetElementType()))
784      continue;
785    ++count;
786  }
787  return count;
788}
789
790CXFA_Node* CXFA_Node::GetChildInternal(size_t index,
791                                       XFA_Element eType,
792                                       bool bOnlyChild) {
793  size_t count = 0;
794  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNextSibling()) {
795    if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
796      continue;
797    if (bOnlyChild && HasProperty(pNode->GetElementType()))
798      continue;
799    if (count == index)
800      return pNode;
801
802    ++count;
803  }
804  return nullptr;
805}
806
807int32_t CXFA_Node::InsertChild(int32_t index, CXFA_Node* pNode) {
808  ASSERT(!pNode->m_pNext);
809  pNode->m_pParent = this;
810  bool ret = m_pDocument->RemovePurgeNode(pNode);
811  ASSERT(ret);
812  (void)ret;  // Avoid unused variable warning.
813
814  if (!m_pChild || index == 0) {
815    if (index > 0) {
816      return -1;
817    }
818    pNode->m_pNext = m_pChild;
819    m_pChild = pNode;
820    index = 0;
821  } else if (index < 0) {
822    m_pLastChild->m_pNext = pNode;
823  } else {
824    CXFA_Node* pPrev = m_pChild;
825    int32_t iCount = 0;
826    while (++iCount != index && pPrev->m_pNext) {
827      pPrev = pPrev->m_pNext;
828    }
829    if (index > 0 && index != iCount) {
830      return -1;
831    }
832    pNode->m_pNext = pPrev->m_pNext;
833    pPrev->m_pNext = pNode;
834    index = iCount;
835  }
836  if (!pNode->m_pNext) {
837    m_pLastChild = pNode;
838  }
839  ASSERT(m_pLastChild);
840  ASSERT(!m_pLastChild->m_pNext);
841  pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
842  CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
843  if (pNotify)
844    pNotify->OnChildAdded(this);
845
846  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
847    ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent));
848    m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, index);
849    pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode);
850  }
851  return index;
852}
853
854bool CXFA_Node::InsertChild(CXFA_Node* pNode, CXFA_Node* pBeforeNode) {
855  if (!pNode || pNode->m_pParent ||
856      (pBeforeNode && pBeforeNode->m_pParent != this)) {
857    NOTREACHED();
858    return false;
859  }
860  bool ret = m_pDocument->RemovePurgeNode(pNode);
861  ASSERT(ret);
862  (void)ret;  // Avoid unused variable warning.
863
864  int32_t nIndex = -1;
865  pNode->m_pParent = this;
866  if (!m_pChild || pBeforeNode == m_pChild) {
867    pNode->m_pNext = m_pChild;
868    m_pChild = pNode;
869    nIndex = 0;
870  } else if (!pBeforeNode) {
871    pNode->m_pNext = m_pLastChild->m_pNext;
872    m_pLastChild->m_pNext = pNode;
873  } else {
874    nIndex = 1;
875    CXFA_Node* pPrev = m_pChild;
876    while (pPrev->m_pNext != pBeforeNode) {
877      pPrev = pPrev->m_pNext;
878      nIndex++;
879    }
880    pNode->m_pNext = pPrev->m_pNext;
881    pPrev->m_pNext = pNode;
882  }
883  if (!pNode->m_pNext) {
884    m_pLastChild = pNode;
885  }
886  ASSERT(m_pLastChild);
887  ASSERT(!m_pLastChild->m_pNext);
888  pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
889  CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
890  if (pNotify)
891    pNotify->OnChildAdded(this);
892
893  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
894    ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent));
895    m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, nIndex);
896    pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode);
897  }
898  return true;
899}
900
901CXFA_Node* CXFA_Node::Deprecated_GetPrevSibling() {
902  if (!m_pParent) {
903    return nullptr;
904  }
905  for (CXFA_Node* pSibling = m_pParent->m_pChild; pSibling;
906       pSibling = pSibling->m_pNext) {
907    if (pSibling->m_pNext == this) {
908      return pSibling;
909    }
910  }
911  return nullptr;
912}
913
914bool CXFA_Node::RemoveChild(CXFA_Node* pNode, bool bNotify) {
915  if (!pNode || pNode->m_pParent != this) {
916    NOTREACHED();
917    return false;
918  }
919  if (m_pChild == pNode) {
920    m_pChild = pNode->m_pNext;
921    if (m_pLastChild == pNode) {
922      m_pLastChild = pNode->m_pNext;
923    }
924    pNode->m_pNext = nullptr;
925    pNode->m_pParent = nullptr;
926  } else {
927    CXFA_Node* pPrev = pNode->Deprecated_GetPrevSibling();
928    pPrev->m_pNext = pNode->m_pNext;
929    if (m_pLastChild == pNode) {
930      m_pLastChild = pNode->m_pNext ? pNode->m_pNext : pPrev;
931    }
932    pNode->m_pNext = nullptr;
933    pNode->m_pParent = nullptr;
934  }
935  ASSERT(!m_pLastChild || !m_pLastChild->m_pNext);
936  OnRemoved(bNotify);
937  pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren, true);
938  m_pDocument->AddPurgeNode(pNode);
939  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
940    if (pNode->IsAttributeInXML()) {
941      ASSERT(pNode->m_pXMLNode == m_pXMLNode &&
942             m_pXMLNode->GetType() == FX_XMLNODE_Element);
943      if (pNode->m_pXMLNode->GetType() == FX_XMLNODE_Element) {
944        CFX_XMLElement* pXMLElement =
945            static_cast<CFX_XMLElement*>(pNode->m_pXMLNode);
946        WideString wsAttributeName =
947            pNode->JSObject()->GetCData(XFA_Attribute::QualifiedName);
948        pXMLElement->RemoveAttribute(wsAttributeName.c_str());
949      }
950
951      WideString wsName = pNode->JSObject()
952                              ->TryAttribute(XFA_Attribute::Name, false)
953                              .value_or(WideString());
954      CFX_XMLElement* pNewXMLElement = new CFX_XMLElement(wsName);
955      WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
956      if (!wsValue.IsEmpty())
957        pNewXMLElement->SetTextData(WideString(wsValue));
958
959      pNode->m_pXMLNode = pNewXMLElement;
960      pNode->JSObject()->SetEnum(XFA_Attribute::Contains,
961                                 XFA_AttributeEnum::Unknown, false);
962    } else {
963      m_pXMLNode->RemoveChildNode(pNode->m_pXMLNode);
964    }
965    pNode->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
966  }
967  return true;
968}
969
970CXFA_Node* CXFA_Node::GetFirstChildByName(const WideStringView& wsName) const {
971  return GetFirstChildByName(FX_HashCode_GetW(wsName, false));
972}
973
974CXFA_Node* CXFA_Node::GetFirstChildByName(uint32_t dwNameHash) const {
975  for (CXFA_Node* pNode = GetFirstChild(); pNode;
976       pNode = pNode->GetNextSibling()) {
977    if (pNode->GetNameHash() == dwNameHash) {
978      return pNode;
979    }
980  }
981  return nullptr;
982}
983
984CXFA_Node* CXFA_Node::GetFirstChildByClassInternal(XFA_Element eType) const {
985  for (CXFA_Node* pNode = GetFirstChild(); pNode;
986       pNode = pNode->GetNextSibling()) {
987    if (pNode->GetElementType() == eType) {
988      return pNode;
989    }
990  }
991  return nullptr;
992}
993
994CXFA_Node* CXFA_Node::GetNextSameNameSibling(uint32_t dwNameHash) const {
995  for (CXFA_Node* pNode = GetNextSibling(); pNode;
996       pNode = pNode->GetNextSibling()) {
997    if (pNode->GetNameHash() == dwNameHash) {
998      return pNode;
999    }
1000  }
1001  return nullptr;
1002}
1003
1004CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal(
1005    const WideStringView& wsNodeName) const {
1006  return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false));
1007}
1008
1009CXFA_Node* CXFA_Node::GetNextSameClassSiblingInternal(XFA_Element eType) const {
1010  for (CXFA_Node* pNode = GetNextSibling(); pNode;
1011       pNode = pNode->GetNextSibling()) {
1012    if (pNode->GetElementType() == eType) {
1013      return pNode;
1014    }
1015  }
1016  return nullptr;
1017}
1018
1019int32_t CXFA_Node::GetNodeSameNameIndex() const {
1020  CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext();
1021  if (!pScriptContext) {
1022    return -1;
1023  }
1024  return pScriptContext->GetIndexByName(const_cast<CXFA_Node*>(this));
1025}
1026
1027int32_t CXFA_Node::GetNodeSameClassIndex() const {
1028  CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext();
1029  if (!pScriptContext) {
1030    return -1;
1031  }
1032  return pScriptContext->GetIndexByClassName(const_cast<CXFA_Node*>(this));
1033}
1034
1035CXFA_Node* CXFA_Node::GetInstanceMgrOfSubform() {
1036  CXFA_Node* pInstanceMgr = nullptr;
1037  if (m_ePacket == XFA_PacketType::Form) {
1038    CXFA_Node* pParentNode = GetParent();
1039    if (!pParentNode || pParentNode->GetElementType() == XFA_Element::Area) {
1040      return pInstanceMgr;
1041    }
1042    for (CXFA_Node* pNode = GetPrevSibling(); pNode;
1043         pNode = pNode->GetPrevSibling()) {
1044      XFA_Element eType = pNode->GetElementType();
1045      if ((eType == XFA_Element::Subform || eType == XFA_Element::SubformSet) &&
1046          pNode->m_dwNameHash != m_dwNameHash) {
1047        break;
1048      }
1049      if (eType == XFA_Element::InstanceManager) {
1050        WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
1051        WideString wsInstName =
1052            pNode->JSObject()->GetCData(XFA_Attribute::Name);
1053        if (wsInstName.GetLength() > 0 && wsInstName[0] == '_' &&
1054            wsInstName.Right(wsInstName.GetLength() - 1) == wsName) {
1055          pInstanceMgr = pNode;
1056        }
1057        break;
1058      }
1059    }
1060  }
1061  return pInstanceMgr;
1062}
1063
1064CXFA_Occur* CXFA_Node::GetOccurIfExists() {
1065  return GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1066}
1067
1068bool CXFA_Node::HasFlag(XFA_NodeFlag dwFlag) const {
1069  if (m_uNodeFlags & dwFlag)
1070    return true;
1071  if (dwFlag == XFA_NodeFlag_HasRemovedChildren)
1072    return m_pParent && m_pParent->HasFlag(dwFlag);
1073  return false;
1074}
1075
1076void CXFA_Node::SetFlag(uint32_t dwFlag, bool bNotify) {
1077  if (dwFlag == XFA_NodeFlag_Initialized && bNotify && !IsInitialized()) {
1078    CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
1079    if (pNotify) {
1080      pNotify->OnNodeReady(this);
1081    }
1082  }
1083  m_uNodeFlags |= dwFlag;
1084}
1085
1086void CXFA_Node::ClearFlag(uint32_t dwFlag) {
1087  m_uNodeFlags &= ~dwFlag;
1088}
1089
1090void CXFA_Node::ReleaseBindingNodes() {
1091  // Clear any binding nodes as we don't necessarily destruct in an order that
1092  // makes sense.
1093  for (auto& node : binding_nodes_)
1094    node.Release();
1095
1096  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->m_pNext)
1097    pNode->ReleaseBindingNodes();
1098}
1099
1100bool CXFA_Node::IsAttributeInXML() {
1101  return JSObject()->GetEnum(XFA_Attribute::Contains) ==
1102         XFA_AttributeEnum::MetaData;
1103}
1104
1105void CXFA_Node::OnRemoved(bool bNotify) {
1106  if (!bNotify)
1107    return;
1108
1109  CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
1110  if (pNotify)
1111    pNotify->OnChildRemoved();
1112}
1113
1114void CXFA_Node::UpdateNameHash() {
1115  WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
1116  m_dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
1117}
1118
1119CFX_XMLNode* CXFA_Node::CreateXMLMappingNode() {
1120  if (!m_pXMLNode) {
1121    WideString wsTag(JSObject()->GetCData(XFA_Attribute::Name));
1122    m_pXMLNode = new CFX_XMLElement(wsTag);
1123    SetFlag(XFA_NodeFlag_OwnXMLNode, false);
1124  }
1125  return m_pXMLNode;
1126}
1127
1128bool CXFA_Node::IsNeedSavingXMLNode() {
1129  return m_pXMLNode && (GetPacketType() == XFA_PacketType::Datasets ||
1130                        GetElementType() == XFA_Element::Xfa);
1131}
1132
1133CXFA_Node* CXFA_Node::GetItemIfExists(int32_t iIndex) {
1134  int32_t iCount = 0;
1135  uint32_t dwNameHash = 0;
1136  for (CXFA_Node* pNode = GetNextSibling(); pNode;
1137       pNode = pNode->GetNextSibling()) {
1138    XFA_Element eCurType = pNode->GetElementType();
1139    if (eCurType == XFA_Element::InstanceManager)
1140      break;
1141    if ((eCurType != XFA_Element::Subform) &&
1142        (eCurType != XFA_Element::SubformSet)) {
1143      continue;
1144    }
1145    if (iCount == 0) {
1146      WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
1147      WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
1148      if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
1149          wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
1150        return nullptr;
1151      }
1152      dwNameHash = pNode->GetNameHash();
1153    }
1154    if (dwNameHash != pNode->GetNameHash())
1155      break;
1156
1157    iCount++;
1158    if (iCount > iIndex)
1159      return pNode;
1160  }
1161  return nullptr;
1162}
1163
1164int32_t CXFA_Node::GetCount() {
1165  int32_t iCount = 0;
1166  uint32_t dwNameHash = 0;
1167  for (CXFA_Node* pNode = GetNextSibling(); pNode;
1168       pNode = pNode->GetNextSibling()) {
1169    XFA_Element eCurType = pNode->GetElementType();
1170    if (eCurType == XFA_Element::InstanceManager)
1171      break;
1172    if ((eCurType != XFA_Element::Subform) &&
1173        (eCurType != XFA_Element::SubformSet)) {
1174      continue;
1175    }
1176    if (iCount == 0) {
1177      WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
1178      WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
1179      if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
1180          wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
1181        return iCount;
1182      }
1183      dwNameHash = pNode->GetNameHash();
1184    }
1185    if (dwNameHash != pNode->GetNameHash())
1186      break;
1187
1188    iCount++;
1189  }
1190  return iCount;
1191}
1192
1193void CXFA_Node::InsertItem(CXFA_Node* pNewInstance,
1194                           int32_t iPos,
1195                           int32_t iCount,
1196                           bool bMoveDataBindingNodes) {
1197  if (iCount < 0)
1198    iCount = GetCount();
1199  if (iPos < 0)
1200    iPos = iCount;
1201  if (iPos == iCount) {
1202    CXFA_Node* item = GetItemIfExists(iCount - 1);
1203    if (!item)
1204      return;
1205
1206    CXFA_Node* pNextSibling =
1207        iCount > 0 ? item->GetNextSibling() : GetNextSibling();
1208    GetParent()->InsertChild(pNewInstance, pNextSibling);
1209    if (bMoveDataBindingNodes) {
1210      std::set<CXFA_Node*> sNew;
1211      std::set<CXFA_Node*> sAfter;
1212      CXFA_NodeIteratorTemplate<CXFA_Node,
1213                                CXFA_TraverseStrategy_XFAContainerNode>
1214          sIteratorNew(pNewInstance);
1215      for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode;
1216           pNode = sIteratorNew.MoveToNext()) {
1217        CXFA_Node* pDataNode = pNode->GetBindData();
1218        if (!pDataNode)
1219          continue;
1220
1221        sNew.insert(pDataNode);
1222      }
1223      CXFA_NodeIteratorTemplate<CXFA_Node,
1224                                CXFA_TraverseStrategy_XFAContainerNode>
1225          sIteratorAfter(pNextSibling);
1226      for (CXFA_Node* pNode = sIteratorAfter.GetCurrent(); pNode;
1227           pNode = sIteratorAfter.MoveToNext()) {
1228        CXFA_Node* pDataNode = pNode->GetBindData();
1229        if (!pDataNode)
1230          continue;
1231
1232        sAfter.insert(pDataNode);
1233      }
1234      ReorderDataNodes(sNew, sAfter, false);
1235    }
1236  } else {
1237    CXFA_Node* pBeforeInstance = GetItemIfExists(iPos);
1238    if (!pBeforeInstance) {
1239      // TODO(dsinclair): What should happen here?
1240      return;
1241    }
1242
1243    GetParent()->InsertChild(pNewInstance, pBeforeInstance);
1244    if (bMoveDataBindingNodes) {
1245      std::set<CXFA_Node*> sNew;
1246      std::set<CXFA_Node*> sBefore;
1247      CXFA_NodeIteratorTemplate<CXFA_Node,
1248                                CXFA_TraverseStrategy_XFAContainerNode>
1249          sIteratorNew(pNewInstance);
1250      for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode;
1251           pNode = sIteratorNew.MoveToNext()) {
1252        CXFA_Node* pDataNode = pNode->GetBindData();
1253        if (!pDataNode)
1254          continue;
1255
1256        sNew.insert(pDataNode);
1257      }
1258      CXFA_NodeIteratorTemplate<CXFA_Node,
1259                                CXFA_TraverseStrategy_XFAContainerNode>
1260          sIteratorBefore(pBeforeInstance);
1261      for (CXFA_Node* pNode = sIteratorBefore.GetCurrent(); pNode;
1262           pNode = sIteratorBefore.MoveToNext()) {
1263        CXFA_Node* pDataNode = pNode->GetBindData();
1264        if (!pDataNode)
1265          continue;
1266
1267        sBefore.insert(pDataNode);
1268      }
1269      ReorderDataNodes(sNew, sBefore, true);
1270    }
1271  }
1272}
1273
1274void CXFA_Node::RemoveItem(CXFA_Node* pRemoveInstance,
1275                           bool bRemoveDataBinding) {
1276  GetParent()->RemoveChild(pRemoveInstance, true);
1277  if (!bRemoveDataBinding)
1278    return;
1279
1280  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
1281      sIterator(pRemoveInstance);
1282  for (CXFA_Node* pFormNode = sIterator.GetCurrent(); pFormNode;
1283       pFormNode = sIterator.MoveToNext()) {
1284    CXFA_Node* pDataNode = pFormNode->GetBindData();
1285    if (!pDataNode)
1286      continue;
1287
1288    if (pDataNode->RemoveBindItem(pFormNode) == 0) {
1289      if (CXFA_Node* pDataParent = pDataNode->GetParent()) {
1290        pDataParent->RemoveChild(pDataNode, true);
1291      }
1292    }
1293    pFormNode->SetBindingNode(nullptr);
1294  }
1295}
1296
1297CXFA_Node* CXFA_Node::CreateInstanceIfPossible(bool bDataMerge) {
1298  CXFA_Document* pDocument = GetDocument();
1299  CXFA_Node* pTemplateNode = GetTemplateNodeIfExists();
1300  if (!pTemplateNode)
1301    return nullptr;
1302
1303  CXFA_Node* pFormParent = GetParent();
1304  CXFA_Node* pDataScope = nullptr;
1305  for (CXFA_Node* pRootBoundNode = pFormParent;
1306       pRootBoundNode && pRootBoundNode->IsContainerNode();
1307       pRootBoundNode = pRootBoundNode->GetParent()) {
1308    pDataScope = pRootBoundNode->GetBindData();
1309    if (pDataScope)
1310      break;
1311  }
1312  if (!pDataScope) {
1313    pDataScope = ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
1314    ASSERT(pDataScope);
1315  }
1316
1317  CXFA_Node* pInstance = pDocument->DataMerge_CopyContainer(
1318      pTemplateNode, pFormParent, pDataScope, true, bDataMerge, true);
1319  if (pInstance) {
1320    pDocument->DataMerge_UpdateBindingRelations(pInstance);
1321    pFormParent->RemoveChild(pInstance, true);
1322  }
1323  return pInstance;
1324}
1325
1326Optional<bool> CXFA_Node::GetDefaultBoolean(XFA_Attribute attr) const {
1327  Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Boolean);
1328  if (!value)
1329    return {};
1330  return {!!*value};
1331}
1332
1333Optional<int32_t> CXFA_Node::GetDefaultInteger(XFA_Attribute attr) const {
1334  Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Integer);
1335  if (!value)
1336    return {};
1337  return {static_cast<int32_t>(reinterpret_cast<uintptr_t>(*value))};
1338}
1339
1340Optional<CXFA_Measurement> CXFA_Node::GetDefaultMeasurement(
1341    XFA_Attribute attr) const {
1342  Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Measure);
1343  if (!value)
1344    return {};
1345
1346  WideString str = WideString(static_cast<const wchar_t*>(*value));
1347  return {CXFA_Measurement(str.AsStringView())};
1348}
1349
1350Optional<WideString> CXFA_Node::GetDefaultCData(XFA_Attribute attr) const {
1351  Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::CData);
1352  if (!value)
1353    return {};
1354
1355  return {WideString(static_cast<const wchar_t*>(*value))};
1356}
1357
1358Optional<XFA_AttributeEnum> CXFA_Node::GetDefaultEnum(
1359    XFA_Attribute attr) const {
1360  Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Enum);
1361  if (!value)
1362    return {};
1363  return {static_cast<XFA_AttributeEnum>(reinterpret_cast<uintptr_t>(*value))};
1364}
1365
1366Optional<void*> CXFA_Node::GetDefaultValue(XFA_Attribute attr,
1367                                           XFA_AttributeType eType) const {
1368  const AttributeData* data = GetAttributeData(attr);
1369  if (!data)
1370    return {};
1371  if (data->type == eType)
1372    return {data->default_value};
1373  return {};
1374}
1375
1376void CXFA_Node::SendAttributeChangeMessage(XFA_Attribute eAttribute,
1377                                           bool bScriptModify) {
1378  CXFA_LayoutProcessor* pLayoutPro = GetDocument()->GetLayoutProcessor();
1379  if (!pLayoutPro)
1380    return;
1381
1382  CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1383  if (!pNotify)
1384    return;
1385
1386  if (GetPacketType() != XFA_PacketType::Form) {
1387    pNotify->OnValueChanged(this, eAttribute, this, this);
1388    return;
1389  }
1390
1391  bool bNeedFindContainer = false;
1392  switch (GetElementType()) {
1393    case XFA_Element::Caption:
1394      bNeedFindContainer = true;
1395      pNotify->OnValueChanged(this, eAttribute, this, GetParent());
1396      break;
1397    case XFA_Element::Font:
1398    case XFA_Element::Para: {
1399      bNeedFindContainer = true;
1400      CXFA_Node* pParentNode = GetParent();
1401      if (pParentNode->GetElementType() == XFA_Element::Caption) {
1402        pNotify->OnValueChanged(this, eAttribute, pParentNode,
1403                                pParentNode->GetParent());
1404      } else {
1405        pNotify->OnValueChanged(this, eAttribute, this, pParentNode);
1406      }
1407      break;
1408    }
1409    case XFA_Element::Margin: {
1410      bNeedFindContainer = true;
1411      CXFA_Node* pParentNode = GetParent();
1412      XFA_Element eParentType = pParentNode->GetElementType();
1413      if (pParentNode->IsContainerNode()) {
1414        pNotify->OnValueChanged(this, eAttribute, this, pParentNode);
1415      } else if (eParentType == XFA_Element::Caption) {
1416        pNotify->OnValueChanged(this, eAttribute, pParentNode,
1417                                pParentNode->GetParent());
1418      } else {
1419        CXFA_Node* pNode = pParentNode->GetParent();
1420        if (pNode && pNode->GetElementType() == XFA_Element::Ui) {
1421          pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetParent());
1422        }
1423      }
1424      break;
1425    }
1426    case XFA_Element::Comb: {
1427      CXFA_Node* pEditNode = GetParent();
1428      XFA_Element eUIType = pEditNode->GetElementType();
1429      if (pEditNode && (eUIType == XFA_Element::DateTimeEdit ||
1430                        eUIType == XFA_Element::NumericEdit ||
1431                        eUIType == XFA_Element::TextEdit)) {
1432        CXFA_Node* pUINode = pEditNode->GetParent();
1433        if (pUINode) {
1434          pNotify->OnValueChanged(this, eAttribute, pUINode,
1435                                  pUINode->GetParent());
1436        }
1437      }
1438      break;
1439    }
1440    case XFA_Element::Button:
1441    case XFA_Element::Barcode:
1442    case XFA_Element::ChoiceList:
1443    case XFA_Element::DateTimeEdit:
1444    case XFA_Element::NumericEdit:
1445    case XFA_Element::PasswordEdit:
1446    case XFA_Element::TextEdit: {
1447      CXFA_Node* pUINode = GetParent();
1448      if (pUINode) {
1449        pNotify->OnValueChanged(this, eAttribute, pUINode,
1450                                pUINode->GetParent());
1451      }
1452      break;
1453    }
1454    case XFA_Element::CheckButton: {
1455      bNeedFindContainer = true;
1456      CXFA_Node* pUINode = GetParent();
1457      if (pUINode) {
1458        pNotify->OnValueChanged(this, eAttribute, pUINode,
1459                                pUINode->GetParent());
1460      }
1461      break;
1462    }
1463    case XFA_Element::Keep:
1464    case XFA_Element::Bookend:
1465    case XFA_Element::Break:
1466    case XFA_Element::BreakAfter:
1467    case XFA_Element::BreakBefore:
1468    case XFA_Element::Overflow:
1469      bNeedFindContainer = true;
1470      break;
1471    case XFA_Element::Area:
1472    case XFA_Element::Draw:
1473    case XFA_Element::ExclGroup:
1474    case XFA_Element::Field:
1475    case XFA_Element::Subform:
1476    case XFA_Element::SubformSet:
1477      pLayoutPro->AddChangedContainer(this);
1478      pNotify->OnValueChanged(this, eAttribute, this, this);
1479      break;
1480    case XFA_Element::Sharptext:
1481    case XFA_Element::Sharpxml:
1482    case XFA_Element::SharpxHTML: {
1483      CXFA_Node* pTextNode = GetParent();
1484      if (!pTextNode)
1485        return;
1486
1487      CXFA_Node* pValueNode = pTextNode->GetParent();
1488      if (!pValueNode)
1489        return;
1490
1491      XFA_Element eType = pValueNode->GetElementType();
1492      if (eType == XFA_Element::Value) {
1493        bNeedFindContainer = true;
1494        CXFA_Node* pNode = pValueNode->GetParent();
1495        if (pNode && pNode->IsContainerNode()) {
1496          if (bScriptModify)
1497            pValueNode = pNode;
1498
1499          pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode);
1500        } else {
1501          pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetParent());
1502        }
1503      } else {
1504        if (eType == XFA_Element::Items) {
1505          CXFA_Node* pNode = pValueNode->GetParent();
1506          if (pNode && pNode->IsContainerNode()) {
1507            pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode);
1508          }
1509        }
1510      }
1511      break;
1512    }
1513    default:
1514      break;
1515  }
1516
1517  if (!bNeedFindContainer)
1518    return;
1519
1520  CXFA_Node* pParent = this;
1521  while (pParent && !pParent->IsContainerNode())
1522    pParent = pParent->GetParent();
1523
1524  if (pParent)
1525    pLayoutPro->AddChangedContainer(pParent);
1526}
1527
1528void CXFA_Node::SyncValue(const WideString& wsValue, bool bNotify) {
1529  WideString wsFormatValue = wsValue;
1530  CXFA_WidgetAcc* pContainerWidgetAcc = GetContainerWidgetAcc();
1531  if (pContainerWidgetAcc)
1532    wsFormatValue = pContainerWidgetAcc->GetFormatDataValue(wsValue);
1533
1534  JSObject()->SetContent(wsValue, wsFormatValue, bNotify, false, true);
1535}
1536
1537WideString CXFA_Node::GetRawValue() {
1538  return JSObject()->GetContent(false);
1539}
1540
1541int32_t CXFA_Node::GetRotate() {
1542  Optional<int32_t> degrees =
1543      JSObject()->TryInteger(XFA_Attribute::Rotate, false);
1544  return degrees ? XFA_MapRotation(*degrees) / 90 * 90 : 0;
1545}
1546
1547CXFA_Border* CXFA_Node::GetBorderIfExists() const {
1548  return JSObject()->GetProperty<CXFA_Border>(0, XFA_Element::Border);
1549}
1550
1551CXFA_Border* CXFA_Node::GetOrCreateBorderIfPossible() {
1552  return JSObject()->GetOrCreateProperty<CXFA_Border>(0, XFA_Element::Border);
1553}
1554
1555CXFA_Caption* CXFA_Node::GetCaptionIfExists() const {
1556  return JSObject()->GetProperty<CXFA_Caption>(0, XFA_Element::Caption);
1557}
1558
1559CXFA_Font* CXFA_Node::GetOrCreateFontIfPossible() {
1560  return JSObject()->GetOrCreateProperty<CXFA_Font>(0, XFA_Element::Font);
1561}
1562
1563CXFA_Font* CXFA_Node::GetFontIfExists() const {
1564  return JSObject()->GetProperty<CXFA_Font>(0, XFA_Element::Font);
1565}
1566
1567float CXFA_Node::GetFontSize() const {
1568  CXFA_Font* font = GetFontIfExists();
1569  float fFontSize = font ? font->GetFontSize() : 10.0f;
1570  return fFontSize < 0.1f ? 10.0f : fFontSize;
1571}
1572
1573float CXFA_Node::GetLineHeight() const {
1574  float fLineHeight = 0;
1575  CXFA_Para* para = GetParaIfExists();
1576  if (para)
1577    fLineHeight = para->GetLineHeight();
1578
1579  if (fLineHeight < 1)
1580    fLineHeight = GetFontSize() * 1.2f;
1581  return fLineHeight;
1582}
1583
1584FX_ARGB CXFA_Node::GetTextColor() const {
1585  CXFA_Font* font = GetFontIfExists();
1586  return font ? font->GetColor() : 0xFF000000;
1587}
1588
1589CXFA_Margin* CXFA_Node::GetMarginIfExists() const {
1590  return JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
1591}
1592
1593CXFA_Para* CXFA_Node::GetParaIfExists() const {
1594  return JSObject()->GetProperty<CXFA_Para>(0, XFA_Element::Para);
1595}
1596
1597bool CXFA_Node::IsOpenAccess() {
1598  for (auto* pNode = this; pNode; pNode = pNode->GetContainerParent()) {
1599    XFA_AttributeEnum iAcc = pNode->JSObject()->GetEnum(XFA_Attribute::Access);
1600    if (iAcc != XFA_AttributeEnum::Open)
1601      return false;
1602  }
1603  return true;
1604}
1605
1606CXFA_Value* CXFA_Node::GetDefaultValueIfExists() {
1607  CXFA_Node* pTemNode = GetTemplateNodeIfExists();
1608  return pTemNode ? pTemNode->JSObject()->GetProperty<CXFA_Value>(
1609                        0, XFA_Element::Value)
1610                  : nullptr;
1611}
1612
1613CXFA_Value* CXFA_Node::GetFormValueIfExists() const {
1614  return JSObject()->GetProperty<CXFA_Value>(0, XFA_Element::Value);
1615}
1616
1617CXFA_Calculate* CXFA_Node::GetCalculateIfExists() const {
1618  return JSObject()->GetProperty<CXFA_Calculate>(0, XFA_Element::Calculate);
1619}
1620
1621CXFA_Validate* CXFA_Node::GetValidateIfExists() const {
1622  return JSObject()->GetProperty<CXFA_Validate>(0, XFA_Element::Validate);
1623}
1624
1625CXFA_Validate* CXFA_Node::GetOrCreateValidateIfPossible() {
1626  return JSObject()->GetOrCreateProperty<CXFA_Validate>(0,
1627                                                        XFA_Element::Validate);
1628}
1629
1630CXFA_Bind* CXFA_Node::GetBindIfExists() const {
1631  return JSObject()->GetProperty<CXFA_Bind>(0, XFA_Element::Bind);
1632}
1633
1634Optional<float> CXFA_Node::TryWidth() {
1635  return JSObject()->TryMeasureAsFloat(XFA_Attribute::W);
1636}
1637
1638Optional<float> CXFA_Node::TryHeight() {
1639  return JSObject()->TryMeasureAsFloat(XFA_Attribute::H);
1640}
1641
1642Optional<float> CXFA_Node::TryMinWidth() {
1643  return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinW);
1644}
1645
1646Optional<float> CXFA_Node::TryMinHeight() {
1647  return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinH);
1648}
1649
1650Optional<float> CXFA_Node::TryMaxWidth() {
1651  return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxW);
1652}
1653
1654Optional<float> CXFA_Node::TryMaxHeight() {
1655  return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxH);
1656}
1657
1658CXFA_Node* CXFA_Node::GetExclGroupIfExists() {
1659  CXFA_Node* pExcl = GetParent();
1660  if (!pExcl || pExcl->GetElementType() != XFA_Element::ExclGroup)
1661    return nullptr;
1662  return pExcl;
1663}
1664
1665int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
1666                                XFA_AttributeEnum iActivity,
1667                                CXFA_EventParam* pEventParam) {
1668  if (GetElementType() == XFA_Element::Draw)
1669    return XFA_EVENTERROR_NotExist;
1670
1671  std::vector<CXFA_Event*> eventArray = GetWidgetAcc()->GetEventByActivity(
1672      iActivity, pEventParam->m_bIsFormReady);
1673  bool first = true;
1674  int32_t iRet = XFA_EVENTERROR_NotExist;
1675  for (CXFA_Event* event : eventArray) {
1676    int32_t result = ProcessEvent(docView, event, pEventParam);
1677    if (first || result == XFA_EVENTERROR_Success)
1678      iRet = result;
1679    first = false;
1680  }
1681  return iRet;
1682}
1683
1684int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
1685                                CXFA_Event* event,
1686                                CXFA_EventParam* pEventParam) {
1687  if (!event)
1688    return XFA_EVENTERROR_NotExist;
1689
1690  switch (event->GetEventType()) {
1691    case XFA_Element::Execute:
1692      break;
1693    case XFA_Element::Script:
1694      return ExecuteScript(docView, event->GetScriptIfExists(), pEventParam);
1695    case XFA_Element::SignData:
1696      break;
1697    case XFA_Element::Submit: {
1698      CXFA_Submit* submit = event->GetSubmitIfExists();
1699      if (!submit)
1700        return XFA_EVENTERROR_NotExist;
1701      return docView->GetDoc()->GetDocEnvironment()->Submit(docView->GetDoc(),
1702                                                            submit);
1703    }
1704    default:
1705      break;
1706  }
1707  return XFA_EVENTERROR_NotExist;
1708}
1709
1710int32_t CXFA_Node::ProcessCalculate(CXFA_FFDocView* docView) {
1711  if (GetElementType() == XFA_Element::Draw)
1712    return XFA_EVENTERROR_NotExist;
1713
1714  CXFA_Calculate* calc = GetCalculateIfExists();
1715  if (!calc)
1716    return XFA_EVENTERROR_NotExist;
1717  if (IsUserInteractive())
1718    return XFA_EVENTERROR_Disabled;
1719
1720  CXFA_EventParam EventParam;
1721  EventParam.m_eType = XFA_EVENT_Calculate;
1722  int32_t iRet = ExecuteScript(docView, calc->GetScriptIfExists(), &EventParam);
1723  if (iRet != XFA_EVENTERROR_Success)
1724    return iRet;
1725
1726  if (GetRawValue() != EventParam.m_wsResult) {
1727    GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw, EventParam.m_wsResult);
1728    GetWidgetAcc()->UpdateUIDisplay(docView, nullptr);
1729  }
1730  return XFA_EVENTERROR_Success;
1731}
1732
1733void CXFA_Node::ProcessScriptTestValidate(CXFA_FFDocView* docView,
1734                                          CXFA_Validate* validate,
1735                                          int32_t iRet,
1736                                          bool bRetValue,
1737                                          bool bVersionFlag) {
1738  if (iRet != XFA_EVENTERROR_Success)
1739    return;
1740  if (bRetValue)
1741    return;
1742
1743  IXFA_AppProvider* pAppProvider =
1744      docView->GetDoc()->GetApp()->GetAppProvider();
1745  if (!pAppProvider)
1746    return;
1747
1748  WideString wsTitle = pAppProvider->GetAppTitle();
1749  WideString wsScriptMsg = validate->GetScriptMessageText();
1750  if (validate->GetScriptTest() == XFA_AttributeEnum::Warning) {
1751    if (IsUserInteractive())
1752      return;
1753    if (wsScriptMsg.IsEmpty())
1754      wsScriptMsg = GetValidateMessage(false, bVersionFlag);
1755
1756    if (bVersionFlag) {
1757      pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning, XFA_MB_OK);
1758      return;
1759    }
1760    if (pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning,
1761                             XFA_MB_YesNo) == XFA_IDYes) {
1762      SetFlag(XFA_NodeFlag_UserInteractive, false);
1763    }
1764    return;
1765  }
1766
1767  if (wsScriptMsg.IsEmpty())
1768    wsScriptMsg = GetValidateMessage(true, bVersionFlag);
1769  pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
1770}
1771
1772int32_t CXFA_Node::ProcessFormatTestValidate(CXFA_FFDocView* docView,
1773                                             CXFA_Validate* validate,
1774                                             bool bVersionFlag) {
1775  WideString wsRawValue = GetRawValue();
1776  if (!wsRawValue.IsEmpty()) {
1777    WideString wsPicture = validate->GetPicture();
1778    if (wsPicture.IsEmpty())
1779      return XFA_EVENTERROR_NotExist;
1780
1781    IFX_Locale* pLocale = GetLocale();
1782    if (!pLocale)
1783      return XFA_EVENTERROR_NotExist;
1784
1785    CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
1786    if (!lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale,
1787                               nullptr)) {
1788      IXFA_AppProvider* pAppProvider =
1789          docView->GetDoc()->GetApp()->GetAppProvider();
1790      if (!pAppProvider)
1791        return XFA_EVENTERROR_NotExist;
1792
1793      WideString wsFormatMsg = validate->GetFormatMessageText();
1794      WideString wsTitle = pAppProvider->GetAppTitle();
1795      if (validate->GetFormatTest() == XFA_AttributeEnum::Error) {
1796        if (wsFormatMsg.IsEmpty())
1797          wsFormatMsg = GetValidateMessage(true, bVersionFlag);
1798        pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
1799        return XFA_EVENTERROR_Success;
1800      }
1801      if (IsUserInteractive())
1802        return XFA_EVENTERROR_NotExist;
1803      if (wsFormatMsg.IsEmpty())
1804        wsFormatMsg = GetValidateMessage(false, bVersionFlag);
1805
1806      if (bVersionFlag) {
1807        pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
1808                             XFA_MB_OK);
1809        return XFA_EVENTERROR_Success;
1810      }
1811      if (pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
1812                               XFA_MB_YesNo) == XFA_IDYes) {
1813        SetFlag(XFA_NodeFlag_UserInteractive, false);
1814      }
1815      return XFA_EVENTERROR_Success;
1816    }
1817  }
1818  return XFA_EVENTERROR_NotExist;
1819}
1820
1821int32_t CXFA_Node::ProcessNullTestValidate(CXFA_FFDocView* docView,
1822                                           CXFA_Validate* validate,
1823                                           int32_t iFlags,
1824                                           bool bVersionFlag) {
1825  if (!GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw).IsEmpty())
1826    return XFA_EVENTERROR_Success;
1827  if (GetWidgetAcc()->IsNull() && GetWidgetAcc()->IsPreNull())
1828    return XFA_EVENTERROR_Success;
1829
1830  XFA_AttributeEnum eNullTest = validate->GetNullTest();
1831  WideString wsNullMsg = validate->GetNullMessageText();
1832  if (iFlags & 0x01) {
1833    int32_t iRet = XFA_EVENTERROR_Success;
1834    if (eNullTest != XFA_AttributeEnum::Disabled)
1835      iRet = XFA_EVENTERROR_Error;
1836
1837    if (!wsNullMsg.IsEmpty()) {
1838      if (eNullTest != XFA_AttributeEnum::Disabled) {
1839        docView->m_arrNullTestMsg.push_back(wsNullMsg);
1840        return XFA_EVENTERROR_Error;
1841      }
1842      return XFA_EVENTERROR_Success;
1843    }
1844    return iRet;
1845  }
1846  if (wsNullMsg.IsEmpty() && bVersionFlag &&
1847      eNullTest != XFA_AttributeEnum::Disabled) {
1848    return XFA_EVENTERROR_Error;
1849  }
1850  IXFA_AppProvider* pAppProvider =
1851      docView->GetDoc()->GetApp()->GetAppProvider();
1852  if (!pAppProvider)
1853    return XFA_EVENTERROR_NotExist;
1854
1855  WideString wsCaptionName;
1856  WideString wsTitle = pAppProvider->GetAppTitle();
1857  switch (eNullTest) {
1858    case XFA_AttributeEnum::Error: {
1859      if (wsNullMsg.IsEmpty()) {
1860        wsCaptionName = GetValidateCaptionName(bVersionFlag);
1861        wsNullMsg =
1862            WideString::Format(L"%ls cannot be blank.", wsCaptionName.c_str());
1863      }
1864      pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Status, XFA_MB_OK);
1865      return XFA_EVENTERROR_Error;
1866    }
1867    case XFA_AttributeEnum::Warning: {
1868      if (IsUserInteractive())
1869        return true;
1870
1871      if (wsNullMsg.IsEmpty()) {
1872        wsCaptionName = GetValidateCaptionName(bVersionFlag);
1873        wsNullMsg = WideString::Format(
1874            L"%ls cannot be blank. To ignore validations for %ls, click "
1875            L"Ignore.",
1876            wsCaptionName.c_str(), wsCaptionName.c_str());
1877      }
1878      if (pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Warning,
1879                               XFA_MB_YesNo) == XFA_IDYes) {
1880        SetFlag(XFA_NodeFlag_UserInteractive, false);
1881      }
1882      return XFA_EVENTERROR_Error;
1883    }
1884    case XFA_AttributeEnum::Disabled:
1885    default:
1886      break;
1887  }
1888  return XFA_EVENTERROR_Success;
1889}
1890
1891int32_t CXFA_Node::ProcessValidate(CXFA_FFDocView* docView, int32_t iFlags) {
1892  if (GetElementType() == XFA_Element::Draw)
1893    return XFA_EVENTERROR_NotExist;
1894
1895  CXFA_Validate* validate = GetValidateIfExists();
1896  if (!validate)
1897    return XFA_EVENTERROR_NotExist;
1898
1899  bool bInitDoc = validate->NeedsInitApp();
1900  bool bStatus = docView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
1901  int32_t iFormat = 0;
1902  int32_t iRet = XFA_EVENTERROR_NotExist;
1903  CXFA_Script* script = validate->GetScriptIfExists();
1904  bool bRet = false;
1905  bool hasBoolResult = (bInitDoc || bStatus) && GetRawValue().IsEmpty();
1906  if (script) {
1907    CXFA_EventParam eParam;
1908    eParam.m_eType = XFA_EVENT_Validate;
1909    eParam.m_pTarget = GetWidgetAcc();
1910    std::tie(iRet, bRet) = ExecuteBoolScript(docView, script, &eParam);
1911  }
1912
1913  XFA_VERSION version = docView->GetDoc()->GetXFADoc()->GetCurVersionMode();
1914  bool bVersionFlag = false;
1915  if (version < XFA_VERSION_208)
1916    bVersionFlag = true;
1917
1918  if (bInitDoc) {
1919    validate->ClearFlag(XFA_NodeFlag_NeedsInitApp);
1920  } else {
1921    iFormat = ProcessFormatTestValidate(docView, validate, bVersionFlag);
1922    if (!bVersionFlag) {
1923      bVersionFlag =
1924          docView->GetDoc()->GetXFADoc()->HasFlag(XFA_DOCFLAG_Scripting);
1925    }
1926
1927    iRet |= ProcessNullTestValidate(docView, validate, iFlags, bVersionFlag);
1928  }
1929
1930  if (iFormat != XFA_EVENTERROR_Success && hasBoolResult)
1931    ProcessScriptTestValidate(docView, validate, iRet, bRet, bVersionFlag);
1932
1933  return iRet | iFormat;
1934}
1935
1936WideString CXFA_Node::GetValidateCaptionName(bool bVersionFlag) {
1937  WideString wsCaptionName;
1938
1939  if (!bVersionFlag) {
1940    CXFA_Caption* caption = GetCaptionIfExists();
1941    if (caption) {
1942      CXFA_Value* capValue = caption->GetValueIfExists();
1943      if (capValue) {
1944        CXFA_Text* captionText = capValue->GetTextIfExists();
1945        if (captionText)
1946          wsCaptionName = captionText->GetContent();
1947      }
1948    }
1949  }
1950  if (!wsCaptionName.IsEmpty())
1951    return wsCaptionName;
1952  return JSObject()->GetCData(XFA_Attribute::Name);
1953}
1954
1955WideString CXFA_Node::GetValidateMessage(bool bError, bool bVersionFlag) {
1956  WideString wsCaptionName = GetValidateCaptionName(bVersionFlag);
1957  if (bVersionFlag)
1958    return WideString::Format(L"%ls validation failed", wsCaptionName.c_str());
1959  if (bError) {
1960    return WideString::Format(L"The value you entered for %ls is invalid.",
1961                              wsCaptionName.c_str());
1962  }
1963  return WideString::Format(
1964      L"The value you entered for %ls is invalid. To ignore "
1965      L"validations for %ls, click Ignore.",
1966      wsCaptionName.c_str(), wsCaptionName.c_str());
1967}
1968
1969int32_t CXFA_Node::ExecuteScript(CXFA_FFDocView* docView,
1970                                 CXFA_Script* script,
1971                                 CXFA_EventParam* pEventParam) {
1972  bool bRet;
1973  int32_t iRet;
1974  std::tie(iRet, bRet) = ExecuteBoolScript(docView, script, pEventParam);
1975  return iRet;
1976}
1977
1978std::pair<int32_t, bool> CXFA_Node::ExecuteBoolScript(
1979    CXFA_FFDocView* docView,
1980    CXFA_Script* script,
1981    CXFA_EventParam* pEventParam) {
1982  if (m_ExecuteRecursionDepth > kMaxExecuteRecursion)
1983    return {XFA_EVENTERROR_Success, false};
1984
1985  ASSERT(pEventParam);
1986  if (!script)
1987    return {XFA_EVENTERROR_NotExist, false};
1988  if (script->GetRunAt() == XFA_AttributeEnum::Server)
1989    return {XFA_EVENTERROR_Disabled, false};
1990
1991  WideString wsExpression = script->GetExpression();
1992  if (wsExpression.IsEmpty())
1993    return {XFA_EVENTERROR_NotExist, false};
1994
1995  CXFA_Script::Type eScriptType = script->GetContentType();
1996  if (eScriptType == CXFA_Script::Type::Unknown)
1997    return {XFA_EVENTERROR_Success, false};
1998
1999  CXFA_FFDoc* pDoc = docView->GetDoc();
2000  CFXJSE_Engine* pContext = pDoc->GetXFADoc()->GetScriptContext();
2001  pContext->SetEventParam(*pEventParam);
2002  pContext->SetRunAtType(script->GetRunAt());
2003
2004  std::vector<CXFA_Node*> refNodes;
2005  if (pEventParam->m_eType == XFA_EVENT_InitCalculate ||
2006      pEventParam->m_eType == XFA_EVENT_Calculate) {
2007    pContext->SetNodesOfRunScript(&refNodes);
2008  }
2009
2010  auto pTmpRetValue = pdfium::MakeUnique<CFXJSE_Value>(pContext->GetIsolate());
2011  bool bRet = false;
2012  {
2013    AutoRestorer<uint8_t> restorer(&m_ExecuteRecursionDepth);
2014    ++m_ExecuteRecursionDepth;
2015    bRet = pContext->RunScript(eScriptType, wsExpression.AsStringView(),
2016                               pTmpRetValue.get(), this);
2017  }
2018
2019  int32_t iRet = XFA_EVENTERROR_Error;
2020  if (bRet) {
2021    iRet = XFA_EVENTERROR_Success;
2022    if (pEventParam->m_eType == XFA_EVENT_Calculate ||
2023        pEventParam->m_eType == XFA_EVENT_InitCalculate) {
2024      if (!pTmpRetValue->IsUndefined()) {
2025        if (!pTmpRetValue->IsNull())
2026          pEventParam->m_wsResult = pTmpRetValue->ToWideString();
2027
2028        iRet = XFA_EVENTERROR_Success;
2029      } else {
2030        iRet = XFA_EVENTERROR_Error;
2031      }
2032      if (pEventParam->m_eType == XFA_EVENT_InitCalculate) {
2033        if ((iRet == XFA_EVENTERROR_Success) &&
2034            (GetRawValue() != pEventParam->m_wsResult)) {
2035          GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw,
2036                                   pEventParam->m_wsResult);
2037          docView->AddValidateWidget(GetWidgetAcc());
2038        }
2039      }
2040      for (CXFA_Node* pRefNode : refNodes) {
2041        if (pRefNode == this)
2042          continue;
2043
2044        CXFA_CalcData* pGlobalData = pRefNode->JSObject()->GetCalcData();
2045        if (!pGlobalData) {
2046          pRefNode->JSObject()->SetCalcData(
2047              pdfium::MakeUnique<CXFA_CalcData>());
2048          pGlobalData = pRefNode->JSObject()->GetCalcData();
2049        }
2050        if (!pdfium::ContainsValue(pGlobalData->m_Globals, this))
2051          pGlobalData->m_Globals.push_back(this);
2052      }
2053    }
2054  }
2055  pContext->SetNodesOfRunScript(nullptr);
2056
2057  return {iRet, pTmpRetValue->IsBoolean() ? pTmpRetValue->ToBoolean() : false};
2058}
2059
2060WideString CXFA_Node::GetBarcodeType() {
2061  CXFA_Node* pUIChild = GetWidgetAcc()->GetUIChild();
2062  return pUIChild
2063             ? WideString(pUIChild->JSObject()->GetCData(XFA_Attribute::Type))
2064             : WideString();
2065}
2066
2067Optional<BC_CHAR_ENCODING> CXFA_Node::GetBarcodeAttribute_CharEncoding() {
2068  Optional<WideString> wsCharEncoding =
2069      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
2070          XFA_Attribute::CharEncoding, true);
2071  if (!wsCharEncoding)
2072    return {};
2073  if (wsCharEncoding->CompareNoCase(L"UTF-16"))
2074    return {CHAR_ENCODING_UNICODE};
2075  if (wsCharEncoding->CompareNoCase(L"UTF-8"))
2076    return {CHAR_ENCODING_UTF8};
2077  return {};
2078}
2079
2080Optional<bool> CXFA_Node::GetBarcodeAttribute_Checksum() {
2081  Optional<XFA_AttributeEnum> checksum =
2082      GetWidgetAcc()->GetUIChild()->JSObject()->TryEnum(XFA_Attribute::Checksum,
2083                                                        true);
2084  if (!checksum)
2085    return {};
2086
2087  switch (*checksum) {
2088    case XFA_AttributeEnum::None:
2089      return {false};
2090    case XFA_AttributeEnum::Auto:
2091      return {true};
2092    case XFA_AttributeEnum::Checksum_1mod10:
2093    case XFA_AttributeEnum::Checksum_1mod10_1mod11:
2094    case XFA_AttributeEnum::Checksum_2mod10:
2095    default:
2096      break;
2097  }
2098  return {};
2099}
2100
2101Optional<int32_t> CXFA_Node::GetBarcodeAttribute_DataLength() {
2102  Optional<WideString> wsDataLength =
2103      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
2104          XFA_Attribute::DataLength, true);
2105  if (!wsDataLength)
2106    return {};
2107
2108  return {FXSYS_wtoi(wsDataLength->c_str())};
2109}
2110
2111Optional<char> CXFA_Node::GetBarcodeAttribute_StartChar() {
2112  Optional<WideString> wsStartEndChar =
2113      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
2114          XFA_Attribute::StartChar, true);
2115  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
2116    return {};
2117
2118  return {static_cast<char>((*wsStartEndChar)[0])};
2119}
2120
2121Optional<char> CXFA_Node::GetBarcodeAttribute_EndChar() {
2122  Optional<WideString> wsStartEndChar =
2123      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(XFA_Attribute::EndChar,
2124                                                         true);
2125  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
2126    return {};
2127
2128  return {static_cast<char>((*wsStartEndChar)[0])};
2129}
2130
2131Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ECLevel() {
2132  Optional<WideString> wsECLevel =
2133      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
2134          XFA_Attribute::ErrorCorrectionLevel, true);
2135  if (!wsECLevel)
2136    return {};
2137  return {FXSYS_wtoi(wsECLevel->c_str())};
2138}
2139
2140Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleWidth() {
2141  Optional<CXFA_Measurement> moduleWidthHeight =
2142      GetWidgetAcc()->GetUIChild()->JSObject()->TryMeasure(
2143          XFA_Attribute::ModuleWidth, true);
2144  if (!moduleWidthHeight)
2145    return {};
2146
2147  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
2148}
2149
2150Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleHeight() {
2151  Optional<CXFA_Measurement> moduleWidthHeight =
2152      GetWidgetAcc()->GetUIChild()->JSObject()->TryMeasure(
2153          XFA_Attribute::ModuleHeight, true);
2154  if (!moduleWidthHeight)
2155    return {};
2156
2157  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
2158}
2159
2160Optional<bool> CXFA_Node::GetBarcodeAttribute_PrintChecksum() {
2161  return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
2162      XFA_Attribute::PrintCheckDigit, true);
2163}
2164
2165Optional<BC_TEXT_LOC> CXFA_Node::GetBarcodeAttribute_TextLocation() {
2166  Optional<XFA_AttributeEnum> textLocation =
2167      GetWidgetAcc()->GetUIChild()->JSObject()->TryEnum(
2168          XFA_Attribute::TextLocation, true);
2169  if (!textLocation)
2170    return {};
2171
2172  switch (*textLocation) {
2173    case XFA_AttributeEnum::None:
2174      return {BC_TEXT_LOC_NONE};
2175    case XFA_AttributeEnum::Above:
2176      return {BC_TEXT_LOC_ABOVE};
2177    case XFA_AttributeEnum::Below:
2178      return {BC_TEXT_LOC_BELOW};
2179    case XFA_AttributeEnum::AboveEmbedded:
2180      return {BC_TEXT_LOC_ABOVEEMBED};
2181    case XFA_AttributeEnum::BelowEmbedded:
2182      return {BC_TEXT_LOC_BELOWEMBED};
2183    default:
2184      break;
2185  }
2186  return {};
2187}
2188
2189Optional<bool> CXFA_Node::GetBarcodeAttribute_Truncate() {
2190  return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
2191      XFA_Attribute::Truncate, true);
2192}
2193
2194Optional<int8_t> CXFA_Node::GetBarcodeAttribute_WideNarrowRatio() {
2195  Optional<WideString> wsWideNarrowRatio =
2196      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
2197          XFA_Attribute::WideNarrowRatio, true);
2198  if (!wsWideNarrowRatio)
2199    return {};
2200
2201  Optional<size_t> ptPos = wsWideNarrowRatio->Find(':');
2202  if (!ptPos)
2203    return {static_cast<int8_t>(FXSYS_wtoi(wsWideNarrowRatio->c_str()))};
2204
2205  int32_t fB = FXSYS_wtoi(
2206      wsWideNarrowRatio->Right(wsWideNarrowRatio->GetLength() - (*ptPos + 1))
2207          .c_str());
2208  if (!fB)
2209    return {0};
2210
2211  int32_t fA = FXSYS_wtoi(wsWideNarrowRatio->Left(*ptPos).c_str());
2212  float result = static_cast<float>(fA) / static_cast<float>(fB);
2213  return {static_cast<int8_t>(result)};
2214}
2215