Home | History | Annotate | Download | only in parser
      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 
     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 
     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 
    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
    156 WideString CXFA_Node::AttributeEnumToName(XFA_AttributeEnum item) {
    157   return g_XFAEnumData[static_cast<int32_t>(item)].pName;
    158 }
    159 
    160 // static
    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 
    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 
    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 
    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 
    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 
    270 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 
    281 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 
    288 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 
    302 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 
    309 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 
    316 bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const {
    317   return !!(m_ValidPackets & (1 << static_cast<uint8_t>(packet)));
    318 }
    319 
    320 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 
    335 bool CXFA_Node::HasProperty(XFA_Element property) const {
    336   return !!GetPropertyData(property);
    337 }
    338 
    339 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 
    344 uint8_t CXFA_Node::PropertyOccuranceCount(XFA_Element property) const {
    345   const PropertyData* data = GetPropertyData(property);
    346   return data ? data->occurance_count : 0;
    347 }
    348 
    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 
    363 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 
    378 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 ....
    383 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 
    389 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 
    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 
    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 
    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 
    482 CXFA_Node* CXFA_Node::GetTemplateNodeIfExists() const {
    483   return m_pAuxNode;
    484 }
    485 
    486 void CXFA_Node::SetTemplateNode(CXFA_Node* pTemplateNode) {
    487   m_pAuxNode = pTemplateNode;
    488 }
    489 
    490 CXFA_Node* CXFA_Node::GetBindData() {
    491   ASSERT(GetPacketType() == XFA_PacketType::Form);
    492   return GetBindingNode();
    493 }
    494 
    495 std::vector<UnownedPtr<CXFA_Node>>* CXFA_Node::GetBindItems() {
    496   return GetBindingNodes();
    497 }
    498 
    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 
    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 
    556 bool CXFA_Node::HasBindItem() {
    557   return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode();
    558 }
    559 
    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 
    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 
    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 
    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 
    742 CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
    743   if (m_ePacket == XFA_PacketType::Datasets)
    744     return m_pAuxNode;
    745   return nullptr;
    746 }
    747 
    748 void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) {
    749   ASSERT(m_ePacket == XFA_PacketType::Datasets);
    750   m_pAuxNode = pDataDescriptionNode;
    751 }
    752 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    970 CXFA_Node* CXFA_Node::GetFirstChildByName(const WideStringView& wsName) const {
    971   return GetFirstChildByName(FX_HashCode_GetW(wsName, false));
    972 }
    973 
    974 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 
    984 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 
    994 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 
   1004 CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal(
   1005     const WideStringView& wsNodeName) const {
   1006   return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false));
   1007 }
   1008 
   1009 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 
   1019 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 
   1027 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 
   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 
   1064 CXFA_Occur* CXFA_Node::GetOccurIfExists() {
   1065   return GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
   1066 }
   1067 
   1068 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 
   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 
   1086 void CXFA_Node::ClearFlag(uint32_t dwFlag) {
   1087   m_uNodeFlags &= ~dwFlag;
   1088 }
   1089 
   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 
   1100 bool CXFA_Node::IsAttributeInXML() {
   1101   return JSObject()->GetEnum(XFA_Attribute::Contains) ==
   1102          XFA_AttributeEnum::MetaData;
   1103 }
   1104 
   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 
   1114 void CXFA_Node::UpdateNameHash() {
   1115   WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
   1116   m_dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
   1117 }
   1118 
   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 
   1128 bool CXFA_Node::IsNeedSavingXMLNode() {
   1129   return m_pXMLNode && (GetPacketType() == XFA_PacketType::Datasets ||
   1130                         GetElementType() == XFA_Element::Xfa);
   1131 }
   1132 
   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 
   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 
   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 
   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 
   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 
   1326 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 
   1333 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 
   1340 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 
   1350 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 
   1358 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 
   1366 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 
   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 
   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 
   1537 WideString CXFA_Node::GetRawValue() {
   1538   return JSObject()->GetContent(false);
   1539 }
   1540 
   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 
   1547 CXFA_Border* CXFA_Node::GetBorderIfExists() const {
   1548   return JSObject()->GetProperty<CXFA_Border>(0, XFA_Element::Border);
   1549 }
   1550 
   1551 CXFA_Border* CXFA_Node::GetOrCreateBorderIfPossible() {
   1552   return JSObject()->GetOrCreateProperty<CXFA_Border>(0, XFA_Element::Border);
   1553 }
   1554 
   1555 CXFA_Caption* CXFA_Node::GetCaptionIfExists() const {
   1556   return JSObject()->GetProperty<CXFA_Caption>(0, XFA_Element::Caption);
   1557 }
   1558 
   1559 CXFA_Font* CXFA_Node::GetOrCreateFontIfPossible() {
   1560   return JSObject()->GetOrCreateProperty<CXFA_Font>(0, XFA_Element::Font);
   1561 }
   1562 
   1563 CXFA_Font* CXFA_Node::GetFontIfExists() const {
   1564   return JSObject()->GetProperty<CXFA_Font>(0, XFA_Element::Font);
   1565 }
   1566 
   1567 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 
   1573 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 
   1584 FX_ARGB CXFA_Node::GetTextColor() const {
   1585   CXFA_Font* font = GetFontIfExists();
   1586   return font ? font->GetColor() : 0xFF000000;
   1587 }
   1588 
   1589 CXFA_Margin* CXFA_Node::GetMarginIfExists() const {
   1590   return JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
   1591 }
   1592 
   1593 CXFA_Para* CXFA_Node::GetParaIfExists() const {
   1594   return JSObject()->GetProperty<CXFA_Para>(0, XFA_Element::Para);
   1595 }
   1596 
   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 
   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 
   1613 CXFA_Value* CXFA_Node::GetFormValueIfExists() const {
   1614   return JSObject()->GetProperty<CXFA_Value>(0, XFA_Element::Value);
   1615 }
   1616 
   1617 CXFA_Calculate* CXFA_Node::GetCalculateIfExists() const {
   1618   return JSObject()->GetProperty<CXFA_Calculate>(0, XFA_Element::Calculate);
   1619 }
   1620 
   1621 CXFA_Validate* CXFA_Node::GetValidateIfExists() const {
   1622   return JSObject()->GetProperty<CXFA_Validate>(0, XFA_Element::Validate);
   1623 }
   1624 
   1625 CXFA_Validate* CXFA_Node::GetOrCreateValidateIfPossible() {
   1626   return JSObject()->GetOrCreateProperty<CXFA_Validate>(0,
   1627                                                         XFA_Element::Validate);
   1628 }
   1629 
   1630 CXFA_Bind* CXFA_Node::GetBindIfExists() const {
   1631   return JSObject()->GetProperty<CXFA_Bind>(0, XFA_Element::Bind);
   1632 }
   1633 
   1634 Optional<float> CXFA_Node::TryWidth() {
   1635   return JSObject()->TryMeasureAsFloat(XFA_Attribute::W);
   1636 }
   1637 
   1638 Optional<float> CXFA_Node::TryHeight() {
   1639   return JSObject()->TryMeasureAsFloat(XFA_Attribute::H);
   1640 }
   1641 
   1642 Optional<float> CXFA_Node::TryMinWidth() {
   1643   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinW);
   1644 }
   1645 
   1646 Optional<float> CXFA_Node::TryMinHeight() {
   1647   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinH);
   1648 }
   1649 
   1650 Optional<float> CXFA_Node::TryMaxWidth() {
   1651   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxW);
   1652 }
   1653 
   1654 Optional<float> CXFA_Node::TryMaxHeight() {
   1655   return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxH);
   1656 }
   1657 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2160 Optional<bool> CXFA_Node::GetBarcodeAttribute_PrintChecksum() {
   2161   return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
   2162       XFA_Attribute::PrintCheckDigit, true);
   2163 }
   2164 
   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 
   2189 Optional<bool> CXFA_Node::GetBarcodeAttribute_Truncate() {
   2190   return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
   2191       XFA_Attribute::Truncate, true);
   2192 }
   2193 
   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