• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
59 namespace {
60 
61 constexpr uint8_t kMaxExecuteRecursion = 2;
62 
NodesSortedByDocumentIdx(const std::set<CXFA_Node * > & rgNodeSet)63 std::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 
78 using CXFA_NodeSetPair = std::pair<std::set<CXFA_Node*>, std::set<CXFA_Node*>>;
79 using CXFA_NodeSetPairMap =
80     std::map<uint32_t, std::unique_ptr<CXFA_NodeSetPair>>;
81 using CXFA_NodeSetPairMapMap =
82     std::map<CXFA_Node*, std::unique_ptr<CXFA_NodeSetPairMap>>;
83 
NodeSetPairForNode(CXFA_Node * pNode,CXFA_NodeSetPairMapMap * pMap)84 CXFA_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 
ReorderDataNodes(const std::set<CXFA_Node * > & sSet1,const std::set<CXFA_Node * > & sSet2,bool bInsertBefore)101 void 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
AttributeEnumToName(XFA_AttributeEnum item)156 WideString CXFA_Node::AttributeEnumToName(XFA_AttributeEnum item) {
157   return g_XFAEnumData[static_cast<int32_t>(item)].pName;
158 }
159 
160 // static
NameToAttributeEnum(const WideStringView & name)161 Optional<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 
CXFA_Node(CXFA_Document * pDoc,XFA_PacketType ePacket,uint32_t validPackets,XFA_ObjectType oType,XFA_Element eType,const PropertyData * properties,const AttributeData * attributes,const WideStringView & elementName,std::unique_ptr<CJX_Object> js_node)175 CXFA_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 
CXFA_Node(CXFA_Document * pDoc,XFA_PacketType ePacket,uint32_t validPackets,XFA_ObjectType oType,XFA_Element eType,const PropertyData * properties,const AttributeData * attributes,const WideStringView & elementName)200 CXFA_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 
~CXFA_Node()218 CXFA_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 
Clone(bool bRecursive)232 CXFA_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 
GetPrevSibling() const270 CXFA_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 
GetNextContainerSibling() const281 CXFA_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 
GetPrevContainerSibling() const288 CXFA_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 
GetFirstContainerChild() const302 CXFA_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 
GetContainerParent() const309 CXFA_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 
IsValidInPacket(XFA_PacketType packet) const316 bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const {
317   return !!(m_ValidPackets & (1 << static_cast<uint8_t>(packet)));
318 }
319 
GetPropertyData(XFA_Element property) const320 const 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 
HasProperty(XFA_Element property) const335 bool CXFA_Node::HasProperty(XFA_Element property) const {
336   return !!GetPropertyData(property);
337 }
338 
HasPropertyFlags(XFA_Element property,uint8_t flags) const339 bool CXFA_Node::HasPropertyFlags(XFA_Element property, uint8_t flags) const {
340   const PropertyData* data = GetPropertyData(property);
341   return data && !!(data->flags & flags);
342 }
343 
PropertyOccuranceCount(XFA_Element property) const344 uint8_t CXFA_Node::PropertyOccuranceCount(XFA_Element property) const {
345   const PropertyData* data = GetPropertyData(property);
346   return data ? data->occurance_count : 0;
347 }
348 
GetFirstPropertyWithFlag(uint8_t flag)349 Optional<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 
GetAttributeData(XFA_Attribute attr) const363 const 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 
HasAttribute(XFA_Attribute attr) const378 bool CXFA_Node::HasAttribute(XFA_Attribute attr) const {
379   return !!GetAttributeData(attr);
380 }
381 
382 // Note: This Method assumes that i is a valid index ....
GetAttribute(size_t i) const383 XFA_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 
GetAttributeType(XFA_Attribute type) const389 XFA_AttributeType CXFA_Node::GetAttributeType(XFA_Attribute type) const {
390   const AttributeData* data = GetAttributeData(type);
391   return data ? data->type : XFA_AttributeType::CData;
392 }
393 
GetNodeList(uint32_t dwTypeFilter,XFA_Element eTypeFilter)394 std::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 
CreateSamePacketNode(XFA_Element eType)456 CXFA_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 
CloneTemplateToForm(bool bRecursive)462 CXFA_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 
GetTemplateNodeIfExists() const482 CXFA_Node* CXFA_Node::GetTemplateNodeIfExists() const {
483   return m_pAuxNode;
484 }
485 
SetTemplateNode(CXFA_Node * pTemplateNode)486 void CXFA_Node::SetTemplateNode(CXFA_Node* pTemplateNode) {
487   m_pAuxNode = pTemplateNode;
488 }
489 
GetBindData()490 CXFA_Node* CXFA_Node::GetBindData() {
491   ASSERT(GetPacketType() == XFA_PacketType::Form);
492   return GetBindingNode();
493 }
494 
GetBindItems()495 std::vector<UnownedPtr<CXFA_Node>>* CXFA_Node::GetBindItems() {
496   return GetBindingNodes();
497 }
498 
AddBindItem(CXFA_Node * pFormNode)499 int32_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 
RemoveBindItem(CXFA_Node * pFormNode)532 int32_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 
HasBindItem()556 bool CXFA_Node::HasBindItem() {
557   return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode();
558 }
559 
GetContainerWidgetAcc()560 CXFA_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 
GetLocale()618 IFX_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 
GetLocaleName()627 Optional<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 
GetIntact()663 XFA_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 
GetDataDescriptionNode()742 CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
743   if (m_ePacket == XFA_PacketType::Datasets)
744     return m_pAuxNode;
745   return nullptr;
746 }
747 
SetDataDescriptionNode(CXFA_Node * pDataDescriptionNode)748 void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) {
749   ASSERT(m_ePacket == XFA_PacketType::Datasets);
750   m_pAuxNode = pDataDescriptionNode;
751 }
752 
GetModelNode()753 CXFA_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 
CountChildren(XFA_Element eType,bool bOnlyChild)778 size_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 
GetChildInternal(size_t index,XFA_Element eType,bool bOnlyChild)790 CXFA_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 
InsertChild(int32_t index,CXFA_Node * pNode)807 int32_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 
InsertChild(CXFA_Node * pNode,CXFA_Node * pBeforeNode)854 bool 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 
Deprecated_GetPrevSibling()901 CXFA_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 
RemoveChild(CXFA_Node * pNode,bool bNotify)914 bool 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 
GetFirstChildByName(const WideStringView & wsName) const970 CXFA_Node* CXFA_Node::GetFirstChildByName(const WideStringView& wsName) const {
971   return GetFirstChildByName(FX_HashCode_GetW(wsName, false));
972 }
973 
GetFirstChildByName(uint32_t dwNameHash) const974 CXFA_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 
GetFirstChildByClassInternal(XFA_Element eType) const984 CXFA_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 
GetNextSameNameSibling(uint32_t dwNameHash) const994 CXFA_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 
GetNextSameNameSiblingInternal(const WideStringView & wsNodeName) const1004 CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal(
1005     const WideStringView& wsNodeName) const {
1006   return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false));
1007 }
1008 
GetNextSameClassSiblingInternal(XFA_Element eType) const1009 CXFA_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 
GetNodeSameNameIndex() const1019 int32_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 
GetNodeSameClassIndex() const1027 int32_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 
GetInstanceMgrOfSubform()1035 CXFA_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 
GetOccurIfExists()1064 CXFA_Occur* CXFA_Node::GetOccurIfExists() {
1065   return GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1066 }
1067 
HasFlag(XFA_NodeFlag dwFlag) const1068 bool 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 
SetFlag(uint32_t dwFlag,bool bNotify)1076 void 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 
ClearFlag(uint32_t dwFlag)1086 void CXFA_Node::ClearFlag(uint32_t dwFlag) {
1087   m_uNodeFlags &= ~dwFlag;
1088 }
1089 
ReleaseBindingNodes()1090 void 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 
IsAttributeInXML()1100 bool CXFA_Node::IsAttributeInXML() {
1101   return JSObject()->GetEnum(XFA_Attribute::Contains) ==
1102          XFA_AttributeEnum::MetaData;
1103 }
1104 
OnRemoved(bool bNotify)1105 void 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 
UpdateNameHash()1114 void CXFA_Node::UpdateNameHash() {
1115   WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
1116   m_dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
1117 }
1118 
CreateXMLMappingNode()1119 CFX_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 
IsNeedSavingXMLNode()1128 bool CXFA_Node::IsNeedSavingXMLNode() {
1129   return m_pXMLNode && (GetPacketType() == XFA_PacketType::Datasets ||
1130                         GetElementType() == XFA_Element::Xfa);
1131 }
1132 
GetItemIfExists(int32_t iIndex)1133 CXFA_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 
GetCount()1164 int32_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 
InsertItem(CXFA_Node * pNewInstance,int32_t iPos,int32_t iCount,bool bMoveDataBindingNodes)1193 void 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 
RemoveItem(CXFA_Node * pRemoveInstance,bool bRemoveDataBinding)1274 void 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 
CreateInstanceIfPossible(bool bDataMerge)1297 CXFA_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 
GetDefaultBoolean(XFA_Attribute attr) const1326 Optional<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 
GetDefaultInteger(XFA_Attribute attr) const1333 Optional<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 
GetDefaultMeasurement(XFA_Attribute attr) const1340 Optional<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 
GetDefaultCData(XFA_Attribute attr) const1350 Optional<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 
GetDefaultEnum(XFA_Attribute attr) const1358 Optional<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 
GetDefaultValue(XFA_Attribute attr,XFA_AttributeType eType) const1366 Optional<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 
SendAttributeChangeMessage(XFA_Attribute eAttribute,bool bScriptModify)1376 void 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 
SyncValue(const WideString & wsValue,bool bNotify)1528 void 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 
GetRawValue()1537 WideString CXFA_Node::GetRawValue() {
1538   return JSObject()->GetContent(false);
1539 }
1540 
GetRotate()1541 int32_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 
GetBorderIfExists() const1547 CXFA_Border* CXFA_Node::GetBorderIfExists() const {
1548   return JSObject()->GetProperty<CXFA_Border>(0, XFA_Element::Border);
1549 }
1550 
GetOrCreateBorderIfPossible()1551 CXFA_Border* CXFA_Node::GetOrCreateBorderIfPossible() {
1552   return JSObject()->GetOrCreateProperty<CXFA_Border>(0, XFA_Element::Border);
1553 }
1554 
GetCaptionIfExists() const1555 CXFA_Caption* CXFA_Node::GetCaptionIfExists() const {
1556   return JSObject()->GetProperty<CXFA_Caption>(0, XFA_Element::Caption);
1557 }
1558 
GetOrCreateFontIfPossible()1559 CXFA_Font* CXFA_Node::GetOrCreateFontIfPossible() {
1560   return JSObject()->GetOrCreateProperty<CXFA_Font>(0, XFA_Element::Font);
1561 }
1562 
GetFontIfExists() const1563 CXFA_Font* CXFA_Node::GetFontIfExists() const {
1564   return JSObject()->GetProperty<CXFA_Font>(0, XFA_Element::Font);
1565 }
1566 
GetFontSize() const1567 float 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 
GetLineHeight() const1573 float 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 
GetTextColor() const1584 FX_ARGB CXFA_Node::GetTextColor() const {
1585   CXFA_Font* font = GetFontIfExists();
1586   return font ? font->GetColor() : 0xFF000000;
1587 }
1588 
GetMarginIfExists() const1589 CXFA_Margin* CXFA_Node::GetMarginIfExists() const {
1590   return JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
1591 }
1592 
GetParaIfExists() const1593 CXFA_Para* CXFA_Node::GetParaIfExists() const {
1594   return JSObject()->GetProperty<CXFA_Para>(0, XFA_Element::Para);
1595 }
1596 
IsOpenAccess()1597 bool 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 
GetDefaultValueIfExists()1606 CXFA_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 
GetFormValueIfExists() const1613 CXFA_Value* CXFA_Node::GetFormValueIfExists() const {
1614   return JSObject()->GetProperty<CXFA_Value>(0, XFA_Element::Value);
1615 }
1616 
GetCalculateIfExists() const1617 CXFA_Calculate* CXFA_Node::GetCalculateIfExists() const {
1618   return JSObject()->GetProperty<CXFA_Calculate>(0, XFA_Element::Calculate);
1619 }
1620 
GetValidateIfExists() const1621 CXFA_Validate* CXFA_Node::GetValidateIfExists() const {
1622   return JSObject()->GetProperty<CXFA_Validate>(0, XFA_Element::Validate);
1623 }
1624 
GetOrCreateValidateIfPossible()1625 CXFA_Validate* CXFA_Node::GetOrCreateValidateIfPossible() {
1626   return JSObject()->GetOrCreateProperty<CXFA_Validate>(0,
1627                                                         XFA_Element::Validate);
1628 }
1629 
GetBindIfExists() const1630 CXFA_Bind* CXFA_Node::GetBindIfExists() const {
1631   return JSObject()->GetProperty<CXFA_Bind>(0, XFA_Element::Bind);
1632 }
1633 
TryWidth()1634 Optional<float> CXFA_Node::TryWidth() {
1635   return JSObject()->TryMeasureAsFloat(XFA_Attribute::W);
1636 }
1637 
TryHeight()1638 Optional<float> CXFA_Node::TryHeight() {
1639   return JSObject()->TryMeasureAsFloat(XFA_Attribute::H);
1640 }
1641 
TryMinWidth()1642 Optional<float> CXFA_Node::TryMinWidth() {
1643   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinW);
1644 }
1645 
TryMinHeight()1646 Optional<float> CXFA_Node::TryMinHeight() {
1647   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinH);
1648 }
1649 
TryMaxWidth()1650 Optional<float> CXFA_Node::TryMaxWidth() {
1651   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxW);
1652 }
1653 
TryMaxHeight()1654 Optional<float> CXFA_Node::TryMaxHeight() {
1655   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxH);
1656 }
1657 
GetExclGroupIfExists()1658 CXFA_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 
ProcessEvent(CXFA_FFDocView * docView,XFA_AttributeEnum iActivity,CXFA_EventParam * pEventParam)1665 int32_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 
ProcessEvent(CXFA_FFDocView * docView,CXFA_Event * event,CXFA_EventParam * pEventParam)1684 int32_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 
ProcessCalculate(CXFA_FFDocView * docView)1710 int32_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 
ProcessScriptTestValidate(CXFA_FFDocView * docView,CXFA_Validate * validate,int32_t iRet,bool bRetValue,bool bVersionFlag)1733 void 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 
ProcessFormatTestValidate(CXFA_FFDocView * docView,CXFA_Validate * validate,bool bVersionFlag)1772 int32_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 
ProcessNullTestValidate(CXFA_FFDocView * docView,CXFA_Validate * validate,int32_t iFlags,bool bVersionFlag)1821 int32_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 
ProcessValidate(CXFA_FFDocView * docView,int32_t iFlags)1891 int32_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 
GetValidateCaptionName(bool bVersionFlag)1936 WideString 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 
GetValidateMessage(bool bError,bool bVersionFlag)1955 WideString 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 
ExecuteScript(CXFA_FFDocView * docView,CXFA_Script * script,CXFA_EventParam * pEventParam)1969 int32_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 
ExecuteBoolScript(CXFA_FFDocView * docView,CXFA_Script * script,CXFA_EventParam * pEventParam)1978 std::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 
GetBarcodeType()2060 WideString CXFA_Node::GetBarcodeType() {
2061   CXFA_Node* pUIChild = GetWidgetAcc()->GetUIChild();
2062   return pUIChild
2063              ? WideString(pUIChild->JSObject()->GetCData(XFA_Attribute::Type))
2064              : WideString();
2065 }
2066 
GetBarcodeAttribute_CharEncoding()2067 Optional<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 
GetBarcodeAttribute_Checksum()2080 Optional<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 
GetBarcodeAttribute_DataLength()2101 Optional<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 
GetBarcodeAttribute_StartChar()2111 Optional<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 
GetBarcodeAttribute_EndChar()2121 Optional<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 
GetBarcodeAttribute_ECLevel()2131 Optional<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 
GetBarcodeAttribute_ModuleWidth()2140 Optional<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 
GetBarcodeAttribute_ModuleHeight()2150 Optional<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 
GetBarcodeAttribute_PrintChecksum()2160 Optional<bool> CXFA_Node::GetBarcodeAttribute_PrintChecksum() {
2161   return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
2162       XFA_Attribute::PrintCheckDigit, true);
2163 }
2164 
GetBarcodeAttribute_TextLocation()2165 Optional<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 
GetBarcodeAttribute_Truncate()2189 Optional<bool> CXFA_Node::GetBarcodeAttribute_Truncate() {
2190   return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
2191       XFA_Attribute::Truncate, true);
2192 }
2193 
GetBarcodeAttribute_WideNarrowRatio()2194 Optional<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