// Copyright 2016 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/parser/cxfa_node.h" #include #include #include #include #include #include "core/fxcrt/cfx_decimal.h" #include "core/fxcrt/cfx_memorystream.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/xml/cfx_xmlelement.h" #include "core/fxcrt/xml/cfx_xmlnode.h" #include "core/fxcrt/xml/cfx_xmltext.h" #include "fxjs/cfxjse_engine.h" #include "fxjs/cfxjse_value.h" #include "third_party/base/logging.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/cxfa_ffnotify.h" #include "xfa/fxfa/cxfa_ffwidget.h" #include "xfa/fxfa/parser/cxfa_arraynodelist.h" #include "xfa/fxfa/parser/cxfa_attachnodelist.h" #include "xfa/fxfa/parser/cxfa_document.h" #include "xfa/fxfa/parser/cxfa_keep.h" #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_measurement.h" #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h" #include "xfa/fxfa/parser/cxfa_occur.h" #include "xfa/fxfa/parser/cxfa_simple_parser.h" #include "xfa/fxfa/parser/cxfa_subform.h" #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h" #include "xfa/fxfa/parser/xfa_basic_data.h" #include "xfa/fxfa/parser/xfa_utils.h" namespace { std::vector NodesSortedByDocumentIdx( const std::set& rgNodeSet) { if (rgNodeSet.empty()) return std::vector(); std::vector rgNodeArray; CXFA_Node* pCommonParent = (*rgNodeSet.begin())->GetNodeItem(XFA_NODEITEM_Parent); for (CXFA_Node* pNode = pCommonParent->GetNodeItem(XFA_NODEITEM_FirstChild); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pdfium::ContainsValue(rgNodeSet, pNode)) rgNodeArray.push_back(pNode); } return rgNodeArray; } using CXFA_NodeSetPair = std::pair, std::set>; using CXFA_NodeSetPairMap = std::map>; using CXFA_NodeSetPairMapMap = std::map>; CXFA_NodeSetPair* NodeSetPairForNode(CXFA_Node* pNode, CXFA_NodeSetPairMapMap* pMap) { CXFA_Node* pParentNode = pNode->GetNodeItem(XFA_NODEITEM_Parent); uint32_t dwNameHash = pNode->GetNameHash(); if (!pParentNode || !dwNameHash) return nullptr; if (!(*pMap)[pParentNode]) (*pMap)[pParentNode] = pdfium::MakeUnique(); CXFA_NodeSetPairMap* pNodeSetPairMap = (*pMap)[pParentNode].get(); if (!(*pNodeSetPairMap)[dwNameHash]) (*pNodeSetPairMap)[dwNameHash] = pdfium::MakeUnique(); return (*pNodeSetPairMap)[dwNameHash].get(); } void ReorderDataNodes(const std::set& sSet1, const std::set& sSet2, bool bInsertBefore) { CXFA_NodeSetPairMapMap rgMap; for (CXFA_Node* pNode : sSet1) { CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap); if (pNodeSetPair) pNodeSetPair->first.insert(pNode); } for (CXFA_Node* pNode : sSet2) { CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap); if (pNodeSetPair) { if (pdfium::ContainsValue(pNodeSetPair->first, pNode)) pNodeSetPair->first.erase(pNode); else pNodeSetPair->second.insert(pNode); } } for (const auto& iter1 : rgMap) { CXFA_NodeSetPairMap* pNodeSetPairMap = iter1.second.get(); if (!pNodeSetPairMap) continue; for (const auto& iter2 : *pNodeSetPairMap) { CXFA_NodeSetPair* pNodeSetPair = iter2.second.get(); if (!pNodeSetPair) continue; if (!pNodeSetPair->first.empty() && !pNodeSetPair->second.empty()) { std::vector rgNodeArray1 = NodesSortedByDocumentIdx(pNodeSetPair->first); std::vector rgNodeArray2 = NodesSortedByDocumentIdx(pNodeSetPair->second); CXFA_Node* pParentNode = nullptr; CXFA_Node* pBeforeNode = nullptr; if (bInsertBefore) { pBeforeNode = rgNodeArray2.front(); pParentNode = pBeforeNode->GetNodeItem(XFA_NODEITEM_Parent); } else { CXFA_Node* pLastNode = rgNodeArray2.back(); pParentNode = pLastNode->GetNodeItem(XFA_NODEITEM_Parent); pBeforeNode = pLastNode->GetNodeItem(XFA_NODEITEM_NextSibling); } for (auto* pCurNode : rgNodeArray1) { pParentNode->RemoveChild(pCurNode, true); pParentNode->InsertChild(pCurNode, pBeforeNode); } } } pNodeSetPairMap->clear(); } } } // namespace // static WideString CXFA_Node::AttributeEnumToName(XFA_AttributeEnum item) { return g_XFAEnumData[static_cast(item)].pName; } // static Optional CXFA_Node::NameToAttributeEnum( const WideStringView& name) { if (name.IsEmpty()) return {}; auto* it = std::lower_bound(g_XFAEnumData, g_XFAEnumData + g_iXFAEnumCount, FX_HashCode_GetW(name, false), [](const XFA_AttributeEnumInfo& arg, uint32_t hash) { return arg.uHash < hash; }); if (it != g_XFAEnumData + g_iXFAEnumCount && name == it->pName) return {it->eName}; return {}; } CXFA_Node::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 js_node) : CXFA_Object(pDoc, oType, eType, elementName, std::move(js_node)), m_Properties(properties), m_Attributes(attributes), m_ValidPackets(validPackets), m_pNext(nullptr), m_pChild(nullptr), m_pLastChild(nullptr), m_pParent(nullptr), m_pXMLNode(nullptr), m_ePacket(ePacket), m_uNodeFlags(XFA_NodeFlag_None), m_dwNameHash(0), m_pAuxNode(nullptr) { ASSERT(m_pDocument); } CXFA_Node::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) : CXFA_Node(pDoc, ePacket, validPackets, oType, eType, properties, attributes, elementName, pdfium::MakeUnique(this)) {} CXFA_Node::~CXFA_Node() { ASSERT(!m_pParent); CXFA_Node* pNode = m_pChild; while (pNode) { CXFA_Node* pNext = pNode->m_pNext; pNode->m_pParent = nullptr; delete pNode; pNode = pNext; } if (m_pXMLNode && IsOwnXMLNode()) delete m_pXMLNode; } CXFA_Node* CXFA_Node::Clone(bool bRecursive) { CXFA_Node* pClone = m_pDocument->CreateNode(m_ePacket, m_elementType); if (!pClone) return nullptr; JSObject()->MergeAllData(pClone); pClone->UpdateNameHash(); if (IsNeedSavingXMLNode()) { std::unique_ptr pCloneXML; if (IsAttributeInXML()) { WideString wsName = JSObject() ->TryAttribute(XFA_Attribute::Name, false) .value_or(WideString()); auto pCloneXMLElement = pdfium::MakeUnique(wsName); WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value); if (!wsValue.IsEmpty()) pCloneXMLElement->SetTextData(WideString(wsValue)); pCloneXML.reset(pCloneXMLElement.release()); pClone->JSObject()->SetEnum(XFA_Attribute::Contains, XFA_AttributeEnum::Unknown, false); } else { pCloneXML = m_pXMLNode->Clone(); } pClone->SetXMLMappingNode(pCloneXML.release()); pClone->SetFlag(XFA_NodeFlag_OwnXMLNode, false); } if (bRecursive) { for (CXFA_Node* pChild = GetNodeItem(XFA_NODEITEM_FirstChild); pChild; pChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling)) { pClone->InsertChild(pChild->Clone(bRecursive), nullptr); } } pClone->SetFlag(XFA_NodeFlag_Initialized, true); pClone->SetBindingNode(nullptr); return pClone; } CXFA_Node* CXFA_Node::GetNodeItem(XFA_NODEITEM eItem) const { switch (eItem) { case XFA_NODEITEM_NextSibling: return m_pNext; case XFA_NODEITEM_FirstChild: return m_pChild; case XFA_NODEITEM_Parent: return m_pParent; case XFA_NODEITEM_PrevSibling: if (m_pParent) { CXFA_Node* pSibling = m_pParent->m_pChild; CXFA_Node* pPrev = nullptr; while (pSibling && pSibling != this) { pPrev = pSibling; pSibling = pSibling->m_pNext; } return pPrev; } return nullptr; default: break; } return nullptr; } bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const { return !!(m_ValidPackets & (1 << static_cast(packet))); } const CXFA_Node::PropertyData* CXFA_Node::GetPropertyData( XFA_Element property) const { if (m_Properties == nullptr) return nullptr; for (size_t i = 0;; ++i) { const PropertyData* data = m_Properties + i; if (data->property == XFA_Element::Unknown) break; if (data->property == property) return data; } return nullptr; } bool CXFA_Node::HasProperty(XFA_Element property) const { return !!GetPropertyData(property); } bool CXFA_Node::HasPropertyFlags(XFA_Element property, uint8_t flags) const { const PropertyData* data = GetPropertyData(property); return data && !!(data->flags & flags); } uint8_t CXFA_Node::PropertyOccuranceCount(XFA_Element property) const { const PropertyData* data = GetPropertyData(property); return data ? data->occurance_count : 0; } Optional CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) { if (m_Properties == nullptr) return {}; for (size_t i = 0;; ++i) { const PropertyData* data = m_Properties + i; if (data->property == XFA_Element::Unknown) break; if (data->flags & flag) return {data->property}; } return {}; } const CXFA_Node::AttributeData* CXFA_Node::GetAttributeData( XFA_Attribute attr) const { if (m_Attributes == nullptr) return nullptr; for (size_t i = 0;; ++i) { const AttributeData* cur_attr = &m_Attributes[i]; if (cur_attr->attribute == XFA_Attribute::Unknown) break; if (cur_attr->attribute == attr) return cur_attr; } return nullptr; } bool CXFA_Node::HasAttribute(XFA_Attribute attr) const { return !!GetAttributeData(attr); } // Note: This Method assumes that i is a valid index .... XFA_Attribute CXFA_Node::GetAttribute(size_t i) const { if (m_Attributes == nullptr) return XFA_Attribute::Unknown; return m_Attributes[i].attribute; } XFA_AttributeType CXFA_Node::GetAttributeType(XFA_Attribute type) const { const AttributeData* data = GetAttributeData(type); return data ? data->type : XFA_AttributeType::CData; } CXFA_Node* CXFA_Node::GetNodeItem(XFA_NODEITEM eItem, XFA_ObjectType eType) const { CXFA_Node* pNode = nullptr; switch (eItem) { case XFA_NODEITEM_NextSibling: pNode = m_pNext; while (pNode && pNode->GetObjectType() != eType) pNode = pNode->m_pNext; break; case XFA_NODEITEM_FirstChild: pNode = m_pChild; while (pNode && pNode->GetObjectType() != eType) pNode = pNode->m_pNext; break; case XFA_NODEITEM_Parent: pNode = m_pParent; while (pNode && pNode->GetObjectType() != eType) pNode = pNode->m_pParent; break; case XFA_NODEITEM_PrevSibling: if (m_pParent) { CXFA_Node* pSibling = m_pParent->m_pChild; while (pSibling && pSibling != this) { if (eType == pSibling->GetObjectType()) pNode = pSibling; pSibling = pSibling->m_pNext; } } break; default: break; } return pNode; } std::vector CXFA_Node::GetNodeList(uint32_t dwTypeFilter, XFA_Element eTypeFilter) { if (eTypeFilter != XFA_Element::Unknown) { std::vector nodes; for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) { if (pChild->GetElementType() == eTypeFilter) nodes.push_back(pChild); } return nodes; } if (dwTypeFilter == (XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties)) { std::vector nodes; for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) nodes.push_back(pChild); return nodes; } if (dwTypeFilter == 0) return std::vector(); bool bFilterChildren = !!(dwTypeFilter & XFA_NODEFILTER_Children); bool bFilterProperties = !!(dwTypeFilter & XFA_NODEFILTER_Properties); bool bFilterOneOfProperties = !!(dwTypeFilter & XFA_NODEFILTER_OneOfProperty); std::vector nodes; for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) { if (!HasProperty(pChild->GetElementType())) { if (bFilterProperties) { nodes.push_back(pChild); } else if (bFilterOneOfProperties && HasPropertyFlags(pChild->GetElementType(), XFA_PROPERTYFLAG_OneOf)) { nodes.push_back(pChild); } else if (bFilterChildren && (pChild->GetElementType() == XFA_Element::Variables || pChild->GetElementType() == XFA_Element::PageSet)) { nodes.push_back(pChild); } } else if (bFilterChildren) { nodes.push_back(pChild); } } if (!bFilterOneOfProperties || !nodes.empty()) return nodes; if (m_Properties == nullptr) return nodes; Optional property = GetFirstPropertyWithFlag(XFA_PROPERTYFLAG_DefaultOneOf); if (!property) return nodes; CXFA_Node* pNewNode = m_pDocument->CreateNode(GetPacketType(), *property); if (pNewNode) { InsertChild(pNewNode, nullptr); pNewNode->SetFlag(XFA_NodeFlag_Initialized, true); nodes.push_back(pNewNode); } return nodes; } CXFA_Node* CXFA_Node::CreateSamePacketNode(XFA_Element eType) { CXFA_Node* pNode = m_pDocument->CreateNode(m_ePacket, eType); pNode->SetFlag(XFA_NodeFlag_Initialized, true); return pNode; } CXFA_Node* CXFA_Node::CloneTemplateToForm(bool bRecursive) { ASSERT(m_ePacket == XFA_PacketType::Template); CXFA_Node* pClone = m_pDocument->CreateNode(XFA_PacketType::Form, m_elementType); if (!pClone) return nullptr; pClone->SetTemplateNode(this); pClone->UpdateNameHash(); pClone->SetXMLMappingNode(GetXMLMappingNode()); if (bRecursive) { for (CXFA_Node* pChild = GetNodeItem(XFA_NODEITEM_FirstChild); pChild; pChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling)) { pClone->InsertChild(pChild->CloneTemplateToForm(bRecursive), nullptr); } } pClone->SetFlag(XFA_NodeFlag_Initialized, true); return pClone; } CXFA_Node* CXFA_Node::GetTemplateNode() const { return m_pAuxNode; } void CXFA_Node::SetTemplateNode(CXFA_Node* pTemplateNode) { m_pAuxNode = pTemplateNode; } CXFA_Node* CXFA_Node::GetBindData() { ASSERT(GetPacketType() == XFA_PacketType::Form); return GetBindingNode(); } std::vector>* CXFA_Node::GetBindItems() { return GetBindingNodes(); } int32_t CXFA_Node::AddBindItem(CXFA_Node* pFormNode) { ASSERT(pFormNode); if (BindsFormItems()) { bool found = false; for (auto& v : binding_nodes_) { if (v.Get() == pFormNode) { found = true; break; } } if (!found) binding_nodes_.emplace_back(pFormNode); return pdfium::CollectionSize(binding_nodes_); } CXFA_Node* pOldFormItem = GetBindingNode(); if (!pOldFormItem) { SetBindingNode(pFormNode); return 1; } if (pOldFormItem == pFormNode) return 1; std::vector> items; items.emplace_back(pOldFormItem); items.emplace_back(pFormNode); SetBindingNodes(std::move(items)); m_uNodeFlags |= XFA_NodeFlag_BindFormItems; return 2; } int32_t CXFA_Node::RemoveBindItem(CXFA_Node* pFormNode) { if (BindsFormItems()) { auto it = std::find_if(binding_nodes_.begin(), binding_nodes_.end(), [&pFormNode](const UnownedPtr& node) { return node.Get() == pFormNode; }); if (it != binding_nodes_.end()) binding_nodes_.erase(it); if (binding_nodes_.size() == 1) { m_uNodeFlags &= ~XFA_NodeFlag_BindFormItems; return 1; } return pdfium::CollectionSize(binding_nodes_); } CXFA_Node* pOldFormItem = GetBindingNode(); if (pOldFormItem != pFormNode) return pOldFormItem ? 1 : 0; SetBindingNode(nullptr); return 0; } bool CXFA_Node::HasBindItem() { return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode(); } CXFA_WidgetAcc* CXFA_Node::GetWidgetAcc() { return JSObject()->GetWidgetAcc(); } CXFA_WidgetAcc* CXFA_Node::GetContainerWidgetAcc() { if (GetPacketType() != XFA_PacketType::Form) return nullptr; XFA_Element eType = GetElementType(); if (eType == XFA_Element::ExclGroup) return nullptr; CXFA_Node* pParentNode = GetNodeItem(XFA_NODEITEM_Parent); if (pParentNode && pParentNode->GetElementType() == XFA_Element::ExclGroup) return nullptr; if (eType == XFA_Element::Field) { CXFA_WidgetAcc* pFieldWidgetAcc = GetWidgetAcc(); if (pFieldWidgetAcc && pFieldWidgetAcc->IsChoiceListMultiSelect()) return nullptr; WideString wsPicture; if (pFieldWidgetAcc) { wsPicture = pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind); } if (!wsPicture.IsEmpty()) return pFieldWidgetAcc; CXFA_Node* pDataNode = GetBindData(); if (!pDataNode) return nullptr; pFieldWidgetAcc = nullptr; for (const auto& pFormNode : *(pDataNode->GetBindItems())) { if (!pFormNode || pFormNode->HasRemovedChildren()) continue; pFieldWidgetAcc = pFormNode->GetWidgetAcc(); if (pFieldWidgetAcc) { wsPicture = pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind); } if (!wsPicture.IsEmpty()) break; pFieldWidgetAcc = nullptr; } return pFieldWidgetAcc; } CXFA_Node* pGrandNode = pParentNode ? pParentNode->GetNodeItem(XFA_NODEITEM_Parent) : nullptr; CXFA_Node* pValueNode = (pParentNode && pParentNode->GetElementType() == XFA_Element::Value) ? pParentNode : nullptr; if (!pValueNode) { pValueNode = (pGrandNode && pGrandNode->GetElementType() == XFA_Element::Value) ? pGrandNode : nullptr; } CXFA_Node* pParentOfValueNode = pValueNode ? pValueNode->GetNodeItem(XFA_NODEITEM_Parent) : nullptr; return pParentOfValueNode ? pParentOfValueNode->GetContainerWidgetAcc() : nullptr; } IFX_Locale* CXFA_Node::GetLocale() { WideString wsLocaleName; if (!GetLocaleName(wsLocaleName)) return nullptr; if (wsLocaleName == L"ambient") return GetDocument()->GetLocalMgr()->GetDefLocale(); return GetDocument()->GetLocalMgr()->GetLocaleByName(wsLocaleName); } bool CXFA_Node::GetLocaleName(WideString& wsLocaleName) { CXFA_Node* pForm = GetDocument()->GetXFAObject(XFA_HASHCODE_Form)->AsNode(); CXFA_Subform* pTopSubform = pForm->GetFirstChildByClass(XFA_Element::Subform); ASSERT(pTopSubform); CXFA_Node* pLocaleNode = this; do { Optional ret = pLocaleNode->JSObject()->TryCData(XFA_Attribute::Locale, false); if (ret) { wsLocaleName = *ret; return true; } pLocaleNode = pLocaleNode->GetNodeItem(XFA_NODEITEM_Parent); } while (pLocaleNode && pLocaleNode != pTopSubform); CXFA_Node* pConfig = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Config)); wsLocaleName = GetDocument()->GetLocalMgr()->GetConfigLocaleName(pConfig); if (!wsLocaleName.IsEmpty()) return true; if (pTopSubform) { Optional ret = pTopSubform->JSObject()->TryCData(XFA_Attribute::Locale, false); if (ret) { wsLocaleName = *ret; return true; } } IFX_Locale* pLocale = GetDocument()->GetLocalMgr()->GetDefLocale(); if (!pLocale) return false; wsLocaleName = pLocale->GetName(); return true; } XFA_AttributeEnum CXFA_Node::GetIntact() { CXFA_Keep* pKeep = GetFirstChildByClass(XFA_Element::Keep); XFA_AttributeEnum eLayoutType = JSObject() ->TryEnum(XFA_Attribute::Layout, true) .value_or(XFA_AttributeEnum::Position); if (pKeep) { Optional intact = pKeep->JSObject()->TryEnum(XFA_Attribute::Intact, false); if (intact) { if (*intact == XFA_AttributeEnum::None && eLayoutType == XFA_AttributeEnum::Row && m_pDocument->GetCurVersionMode() < XFA_VERSION_208) { CXFA_Node* pPreviewRow = GetNodeItem(XFA_NODEITEM_PrevSibling, XFA_ObjectType::ContainerNode); if (pPreviewRow && pPreviewRow->JSObject()->GetEnum(XFA_Attribute::Layout) == XFA_AttributeEnum::Row) { Optional value = pKeep->JSObject()->TryEnum(XFA_Attribute::Previous, false); if (value && (*value == XFA_AttributeEnum::ContentArea || *value == XFA_AttributeEnum::PageArea)) { return XFA_AttributeEnum::ContentArea; } CXFA_Keep* pNode = pPreviewRow->GetFirstChildByClass(XFA_Element::Keep); Optional ret; if (pNode) ret = pNode->JSObject()->TryEnum(XFA_Attribute::Next, false); if (ret && (*ret == XFA_AttributeEnum::ContentArea || *ret == XFA_AttributeEnum::PageArea)) { return XFA_AttributeEnum::ContentArea; } } } return *intact; } } switch (GetElementType()) { case XFA_Element::Subform: switch (eLayoutType) { case XFA_AttributeEnum::Position: case XFA_AttributeEnum::Row: return XFA_AttributeEnum::ContentArea; default: return XFA_AttributeEnum::None; } case XFA_Element::Field: { CXFA_Node* parent = GetNodeItem(XFA_NODEITEM_Parent); if (!parent || parent->GetElementType() == XFA_Element::PageArea) return XFA_AttributeEnum::ContentArea; if (parent->GetIntact() != XFA_AttributeEnum::None) return XFA_AttributeEnum::ContentArea; XFA_AttributeEnum eParLayout = parent->JSObject() ->TryEnum(XFA_Attribute::Layout, true) .value_or(XFA_AttributeEnum::Position); if (eParLayout == XFA_AttributeEnum::Position || eParLayout == XFA_AttributeEnum::Row || eParLayout == XFA_AttributeEnum::Table) { return XFA_AttributeEnum::None; } XFA_VERSION version = m_pDocument->GetCurVersionMode(); if (eParLayout == XFA_AttributeEnum::Tb && version < XFA_VERSION_208) { Optional measureH = JSObject()->TryMeasure(XFA_Attribute::H, false); if (measureH) return XFA_AttributeEnum::ContentArea; } return XFA_AttributeEnum::None; } case XFA_Element::Draw: return XFA_AttributeEnum::ContentArea; default: return XFA_AttributeEnum::None; } } CXFA_Node* CXFA_Node::GetDataDescriptionNode() { if (m_ePacket == XFA_PacketType::Datasets) return m_pAuxNode; return nullptr; } void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) { ASSERT(m_ePacket == XFA_PacketType::Datasets); m_pAuxNode = pDataDescriptionNode; } CXFA_Node* CXFA_Node::GetModelNode() { switch (GetPacketType()) { case XFA_PacketType::Xdp: return m_pDocument->GetRoot(); case XFA_PacketType::Config: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config)); case XFA_PacketType::Template: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Template)); case XFA_PacketType::Form: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form)); case XFA_PacketType::Datasets: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Datasets)); case XFA_PacketType::LocaleSet: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_LocaleSet)); case XFA_PacketType::ConnectionSet: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_ConnectionSet)); case XFA_PacketType::SourceSet: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_SourceSet)); case XFA_PacketType::Xdc: return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Xdc)); default: return this; } } size_t CXFA_Node::CountChildren(XFA_Element eType, bool bOnlyChild) { size_t count = 0; for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown) continue; if (bOnlyChild && HasProperty(pNode->GetElementType())) continue; ++count; } return count; } CXFA_Node* CXFA_Node::GetChildInternal(size_t index, XFA_Element eType, bool bOnlyChild) { size_t count = 0; for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown) continue; if (bOnlyChild && HasProperty(pNode->GetElementType())) continue; if (count == index) return pNode; ++count; } return nullptr; } int32_t CXFA_Node::InsertChild(int32_t index, CXFA_Node* pNode) { ASSERT(!pNode->m_pNext); pNode->m_pParent = this; bool ret = m_pDocument->RemovePurgeNode(pNode); ASSERT(ret); (void)ret; // Avoid unused variable warning. if (!m_pChild || index == 0) { if (index > 0) { return -1; } pNode->m_pNext = m_pChild; m_pChild = pNode; index = 0; } else if (index < 0) { m_pLastChild->m_pNext = pNode; } else { CXFA_Node* pPrev = m_pChild; int32_t iCount = 0; while (++iCount != index && pPrev->m_pNext) { pPrev = pPrev->m_pNext; } if (index > 0 && index != iCount) { return -1; } pNode->m_pNext = pPrev->m_pNext; pPrev->m_pNext = pNode; index = iCount; } if (!pNode->m_pNext) { m_pLastChild = pNode; } ASSERT(m_pLastChild); ASSERT(!m_pLastChild->m_pNext); pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren); CXFA_FFNotify* pNotify = m_pDocument->GetNotify(); if (pNotify) pNotify->OnChildAdded(this); if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) { ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent)); m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, index); pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode); } return index; } bool CXFA_Node::InsertChild(CXFA_Node* pNode, CXFA_Node* pBeforeNode) { if (!pNode || pNode->m_pParent || (pBeforeNode && pBeforeNode->m_pParent != this)) { NOTREACHED(); return false; } bool ret = m_pDocument->RemovePurgeNode(pNode); ASSERT(ret); (void)ret; // Avoid unused variable warning. int32_t nIndex = -1; pNode->m_pParent = this; if (!m_pChild || pBeforeNode == m_pChild) { pNode->m_pNext = m_pChild; m_pChild = pNode; nIndex = 0; } else if (!pBeforeNode) { pNode->m_pNext = m_pLastChild->m_pNext; m_pLastChild->m_pNext = pNode; } else { nIndex = 1; CXFA_Node* pPrev = m_pChild; while (pPrev->m_pNext != pBeforeNode) { pPrev = pPrev->m_pNext; nIndex++; } pNode->m_pNext = pPrev->m_pNext; pPrev->m_pNext = pNode; } if (!pNode->m_pNext) { m_pLastChild = pNode; } ASSERT(m_pLastChild); ASSERT(!m_pLastChild->m_pNext); pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren); CXFA_FFNotify* pNotify = m_pDocument->GetNotify(); if (pNotify) pNotify->OnChildAdded(this); if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) { ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent)); m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, nIndex); pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode); } return true; } CXFA_Node* CXFA_Node::Deprecated_GetPrevSibling() { if (!m_pParent) { return nullptr; } for (CXFA_Node* pSibling = m_pParent->m_pChild; pSibling; pSibling = pSibling->m_pNext) { if (pSibling->m_pNext == this) { return pSibling; } } return nullptr; } bool CXFA_Node::RemoveChild(CXFA_Node* pNode, bool bNotify) { if (!pNode || pNode->m_pParent != this) { NOTREACHED(); return false; } if (m_pChild == pNode) { m_pChild = pNode->m_pNext; if (m_pLastChild == pNode) { m_pLastChild = pNode->m_pNext; } pNode->m_pNext = nullptr; pNode->m_pParent = nullptr; } else { CXFA_Node* pPrev = pNode->Deprecated_GetPrevSibling(); pPrev->m_pNext = pNode->m_pNext; if (m_pLastChild == pNode) { m_pLastChild = pNode->m_pNext ? pNode->m_pNext : pPrev; } pNode->m_pNext = nullptr; pNode->m_pParent = nullptr; } ASSERT(!m_pLastChild || !m_pLastChild->m_pNext); OnRemoved(bNotify); pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren, true); m_pDocument->AddPurgeNode(pNode); if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) { if (pNode->IsAttributeInXML()) { ASSERT(pNode->m_pXMLNode == m_pXMLNode && m_pXMLNode->GetType() == FX_XMLNODE_Element); if (pNode->m_pXMLNode->GetType() == FX_XMLNODE_Element) { CFX_XMLElement* pXMLElement = static_cast(pNode->m_pXMLNode); WideString wsAttributeName = pNode->JSObject()->GetCData(XFA_Attribute::QualifiedName); pXMLElement->RemoveAttribute(wsAttributeName.c_str()); } WideString wsName = pNode->JSObject() ->TryAttribute(XFA_Attribute::Name, false) .value_or(WideString()); CFX_XMLElement* pNewXMLElement = new CFX_XMLElement(wsName); WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value); if (!wsValue.IsEmpty()) pNewXMLElement->SetTextData(WideString(wsValue)); pNode->m_pXMLNode = pNewXMLElement; pNode->JSObject()->SetEnum(XFA_Attribute::Contains, XFA_AttributeEnum::Unknown, false); } else { m_pXMLNode->RemoveChildNode(pNode->m_pXMLNode); } pNode->SetFlag(XFA_NodeFlag_OwnXMLNode, false); } return true; } CXFA_Node* CXFA_Node::GetFirstChildByName(const WideStringView& wsName) const { return GetFirstChildByName(FX_HashCode_GetW(wsName, false)); } CXFA_Node* CXFA_Node::GetFirstChildByName(uint32_t dwNameHash) const { for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_FirstChild); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetNameHash() == dwNameHash) { return pNode; } } return nullptr; } CXFA_Node* CXFA_Node::GetFirstChildByClassInternal(XFA_Element eType) const { for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_FirstChild); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetElementType() == eType) { return pNode; } } return nullptr; } CXFA_Node* CXFA_Node::GetNextSameNameSibling(uint32_t dwNameHash) const { for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_NextSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetNameHash() == dwNameHash) { return pNode; } } return nullptr; } CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal( const WideStringView& wsNodeName) const { return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false)); } CXFA_Node* CXFA_Node::GetNextSameClassSiblingInternal(XFA_Element eType) const { for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_NextSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { if (pNode->GetElementType() == eType) { return pNode; } } return nullptr; } int32_t CXFA_Node::GetNodeSameNameIndex() const { CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext(); if (!pScriptContext) { return -1; } return pScriptContext->GetIndexByName(const_cast(this)); } int32_t CXFA_Node::GetNodeSameClassIndex() const { CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext(); if (!pScriptContext) { return -1; } return pScriptContext->GetIndexByClassName(const_cast(this)); } CXFA_Node* CXFA_Node::GetInstanceMgrOfSubform() { CXFA_Node* pInstanceMgr = nullptr; if (m_ePacket == XFA_PacketType::Form) { CXFA_Node* pParentNode = GetNodeItem(XFA_NODEITEM_Parent); if (!pParentNode || pParentNode->GetElementType() == XFA_Element::Area) { return pInstanceMgr; } for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_PrevSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_PrevSibling)) { XFA_Element eType = pNode->GetElementType(); if ((eType == XFA_Element::Subform || eType == XFA_Element::SubformSet) && pNode->m_dwNameHash != m_dwNameHash) { break; } if (eType == XFA_Element::InstanceManager) { WideString wsName = JSObject()->GetCData(XFA_Attribute::Name); WideString wsInstName = pNode->JSObject()->GetCData(XFA_Attribute::Name); if (wsInstName.GetLength() > 0 && wsInstName[0] == '_' && wsInstName.Right(wsInstName.GetLength() - 1) == wsName) { pInstanceMgr = pNode; } break; } } } return pInstanceMgr; } CXFA_Occur* CXFA_Node::GetOccur() { return GetFirstChildByClass(XFA_Element::Occur); } bool CXFA_Node::HasFlag(XFA_NodeFlag dwFlag) const { if (m_uNodeFlags & dwFlag) return true; if (dwFlag == XFA_NodeFlag_HasRemovedChildren) return m_pParent && m_pParent->HasFlag(dwFlag); return false; } void CXFA_Node::SetFlag(uint32_t dwFlag, bool bNotify) { if (dwFlag == XFA_NodeFlag_Initialized && bNotify && !IsInitialized()) { CXFA_FFNotify* pNotify = m_pDocument->GetNotify(); if (pNotify) { pNotify->OnNodeReady(this); } } m_uNodeFlags |= dwFlag; } void CXFA_Node::ClearFlag(uint32_t dwFlag) { m_uNodeFlags &= ~dwFlag; } void CXFA_Node::ReleaseBindingNodes() { // Clear any binding nodes as we don't necessarily destruct in an order that // makes sense. for (auto& node : binding_nodes_) node.Release(); for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->m_pNext) pNode->ReleaseBindingNodes(); } bool CXFA_Node::IsAttributeInXML() { return JSObject()->GetEnum(XFA_Attribute::Contains) == XFA_AttributeEnum::MetaData; } void CXFA_Node::OnRemoved(bool bNotify) { if (!bNotify) return; CXFA_FFNotify* pNotify = m_pDocument->GetNotify(); if (pNotify) pNotify->OnChildRemoved(); } void CXFA_Node::UpdateNameHash() { WideString wsName = JSObject()->GetCData(XFA_Attribute::Name); m_dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false); } CFX_XMLNode* CXFA_Node::CreateXMLMappingNode() { if (!m_pXMLNode) { WideString wsTag(JSObject()->GetCData(XFA_Attribute::Name)); m_pXMLNode = new CFX_XMLElement(wsTag); SetFlag(XFA_NodeFlag_OwnXMLNode, false); } return m_pXMLNode; } bool CXFA_Node::IsNeedSavingXMLNode() { return m_pXMLNode && (GetPacketType() == XFA_PacketType::Datasets || GetElementType() == XFA_Element::Xfa); } CXFA_Node* CXFA_Node::GetItem(int32_t iIndex) { int32_t iCount = 0; uint32_t dwNameHash = 0; for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_NextSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { XFA_Element eCurType = pNode->GetElementType(); if (eCurType == XFA_Element::InstanceManager) break; if ((eCurType != XFA_Element::Subform) && (eCurType != XFA_Element::SubformSet)) { continue; } if (iCount == 0) { WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name); WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name); if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' || wsInstName.Right(wsInstName.GetLength() - 1) != wsName) { return nullptr; } dwNameHash = pNode->GetNameHash(); } if (dwNameHash != pNode->GetNameHash()) break; iCount++; if (iCount > iIndex) return pNode; } return nullptr; } int32_t CXFA_Node::GetCount() { int32_t iCount = 0; uint32_t dwNameHash = 0; for (CXFA_Node* pNode = GetNodeItem(XFA_NODEITEM_NextSibling); pNode; pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { XFA_Element eCurType = pNode->GetElementType(); if (eCurType == XFA_Element::InstanceManager) break; if ((eCurType != XFA_Element::Subform) && (eCurType != XFA_Element::SubformSet)) { continue; } if (iCount == 0) { WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name); WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name); if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' || wsInstName.Right(wsInstName.GetLength() - 1) != wsName) { return iCount; } dwNameHash = pNode->GetNameHash(); } if (dwNameHash != pNode->GetNameHash()) break; iCount++; } return iCount; } void CXFA_Node::InsertItem(CXFA_Node* pNewInstance, int32_t iPos, int32_t iCount, bool bMoveDataBindingNodes) { if (iCount < 0) iCount = GetCount(); if (iPos < 0) iPos = iCount; if (iPos == iCount) { CXFA_Node* pNextSibling = iCount > 0 ? GetItem(iCount - 1)->GetNodeItem(XFA_NODEITEM_NextSibling) : GetNodeItem(XFA_NODEITEM_NextSibling); GetNodeItem(XFA_NODEITEM_Parent)->InsertChild(pNewInstance, pNextSibling); if (bMoveDataBindingNodes) { std::set sNew; std::set sAfter; CXFA_NodeIteratorTemplate sIteratorNew(pNewInstance); for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode; pNode = sIteratorNew.MoveToNext()) { CXFA_Node* pDataNode = pNode->GetBindData(); if (!pDataNode) continue; sNew.insert(pDataNode); } CXFA_NodeIteratorTemplate sIteratorAfter(pNextSibling); for (CXFA_Node* pNode = sIteratorAfter.GetCurrent(); pNode; pNode = sIteratorAfter.MoveToNext()) { CXFA_Node* pDataNode = pNode->GetBindData(); if (!pDataNode) continue; sAfter.insert(pDataNode); } ReorderDataNodes(sNew, sAfter, false); } } else { CXFA_Node* pBeforeInstance = GetItem(iPos); GetNodeItem(XFA_NODEITEM_Parent) ->InsertChild(pNewInstance, pBeforeInstance); if (bMoveDataBindingNodes) { std::set sNew; std::set sBefore; CXFA_NodeIteratorTemplate sIteratorNew(pNewInstance); for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode; pNode = sIteratorNew.MoveToNext()) { CXFA_Node* pDataNode = pNode->GetBindData(); if (!pDataNode) continue; sNew.insert(pDataNode); } CXFA_NodeIteratorTemplate sIteratorBefore(pBeforeInstance); for (CXFA_Node* pNode = sIteratorBefore.GetCurrent(); pNode; pNode = sIteratorBefore.MoveToNext()) { CXFA_Node* pDataNode = pNode->GetBindData(); if (!pDataNode) continue; sBefore.insert(pDataNode); } ReorderDataNodes(sNew, sBefore, true); } } } void CXFA_Node::RemoveItem(CXFA_Node* pRemoveInstance, bool bRemoveDataBinding) { GetNodeItem(XFA_NODEITEM_Parent)->RemoveChild(pRemoveInstance, true); if (!bRemoveDataBinding) return; CXFA_NodeIteratorTemplate sIterator(pRemoveInstance); for (CXFA_Node* pFormNode = sIterator.GetCurrent(); pFormNode; pFormNode = sIterator.MoveToNext()) { CXFA_Node* pDataNode = pFormNode->GetBindData(); if (!pDataNode) continue; if (pDataNode->RemoveBindItem(pFormNode) == 0) { if (CXFA_Node* pDataParent = pDataNode->GetNodeItem(XFA_NODEITEM_Parent)) { pDataParent->RemoveChild(pDataNode, true); } } pFormNode->SetBindingNode(nullptr); } } CXFA_Node* CXFA_Node::CreateInstance(bool bDataMerge) { CXFA_Document* pDocument = GetDocument(); CXFA_Node* pTemplateNode = GetTemplateNode(); CXFA_Node* pFormParent = GetNodeItem(XFA_NODEITEM_Parent); CXFA_Node* pDataScope = nullptr; for (CXFA_Node* pRootBoundNode = pFormParent; pRootBoundNode && pRootBoundNode->IsContainerNode(); pRootBoundNode = pRootBoundNode->GetNodeItem(XFA_NODEITEM_Parent)) { pDataScope = pRootBoundNode->GetBindData(); if (pDataScope) break; } if (!pDataScope) { pDataScope = ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)); ASSERT(pDataScope); } CXFA_Node* pInstance = pDocument->DataMerge_CopyContainer( pTemplateNode, pFormParent, pDataScope, true, bDataMerge, true); if (pInstance) { pDocument->DataMerge_UpdateBindingRelations(pInstance); pFormParent->RemoveChild(pInstance, true); } return pInstance; } Optional CXFA_Node::GetDefaultBoolean(XFA_Attribute attr) const { Optional value = GetDefaultValue(attr, XFA_AttributeType::Boolean); if (!value) return {}; return {!!*value}; } Optional CXFA_Node::GetDefaultInteger(XFA_Attribute attr) const { Optional value = GetDefaultValue(attr, XFA_AttributeType::Integer); if (!value) return {}; return {static_cast(reinterpret_cast(*value))}; } Optional CXFA_Node::GetDefaultMeasurement( XFA_Attribute attr) const { Optional value = GetDefaultValue(attr, XFA_AttributeType::Measure); if (!value) return {}; WideString str = WideString(static_cast(*value)); return {CXFA_Measurement(str.AsStringView())}; } Optional CXFA_Node::GetDefaultCData(XFA_Attribute attr) const { Optional value = GetDefaultValue(attr, XFA_AttributeType::CData); if (!value) return {}; return {WideString(static_cast(*value))}; } Optional CXFA_Node::GetDefaultEnum( XFA_Attribute attr) const { Optional value = GetDefaultValue(attr, XFA_AttributeType::Enum); if (!value) return {}; return {static_cast(reinterpret_cast(*value))}; } Optional CXFA_Node::GetDefaultValue(XFA_Attribute attr, XFA_AttributeType eType) const { const AttributeData* data = GetAttributeData(attr); if (!data) return {}; if (data->type == eType) return {data->default_value}; return {}; } void CXFA_Node::SendAttributeChangeMessage(XFA_Attribute eAttribute, bool bScriptModify) { CXFA_LayoutProcessor* pLayoutPro = GetDocument()->GetLayoutProcessor(); if (!pLayoutPro) return; CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); if (!pNotify) return; if (GetPacketType() != XFA_PacketType::Form) { pNotify->OnValueChanged(this, eAttribute, this, this); return; } bool bNeedFindContainer = false; switch (GetElementType()) { case XFA_Element::Caption: bNeedFindContainer = true; pNotify->OnValueChanged(this, eAttribute, this, GetNodeItem(XFA_NODEITEM_Parent)); break; case XFA_Element::Font: case XFA_Element::Para: { bNeedFindContainer = true; CXFA_Node* pParentNode = GetNodeItem(XFA_NODEITEM_Parent); if (pParentNode->GetElementType() == XFA_Element::Caption) { pNotify->OnValueChanged(this, eAttribute, pParentNode, pParentNode->GetNodeItem(XFA_NODEITEM_Parent)); } else { pNotify->OnValueChanged(this, eAttribute, this, pParentNode); } break; } case XFA_Element::Margin: { bNeedFindContainer = true; CXFA_Node* pParentNode = GetNodeItem(XFA_NODEITEM_Parent); XFA_Element eParentType = pParentNode->GetElementType(); if (pParentNode->IsContainerNode()) { pNotify->OnValueChanged(this, eAttribute, this, pParentNode); } else if (eParentType == XFA_Element::Caption) { pNotify->OnValueChanged(this, eAttribute, pParentNode, pParentNode->GetNodeItem(XFA_NODEITEM_Parent)); } else { CXFA_Node* pNode = pParentNode->GetNodeItem(XFA_NODEITEM_Parent); if (pNode && pNode->GetElementType() == XFA_Element::Ui) { pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetNodeItem(XFA_NODEITEM_Parent)); } } break; } case XFA_Element::Comb: { CXFA_Node* pEditNode = GetNodeItem(XFA_NODEITEM_Parent); XFA_Element eUIType = pEditNode->GetElementType(); if (pEditNode && (eUIType == XFA_Element::DateTimeEdit || eUIType == XFA_Element::NumericEdit || eUIType == XFA_Element::TextEdit)) { CXFA_Node* pUINode = pEditNode->GetNodeItem(XFA_NODEITEM_Parent); if (pUINode) { pNotify->OnValueChanged(this, eAttribute, pUINode, pUINode->GetNodeItem(XFA_NODEITEM_Parent)); } } break; } case XFA_Element::Button: case XFA_Element::Barcode: case XFA_Element::ChoiceList: case XFA_Element::DateTimeEdit: case XFA_Element::NumericEdit: case XFA_Element::PasswordEdit: case XFA_Element::TextEdit: { CXFA_Node* pUINode = GetNodeItem(XFA_NODEITEM_Parent); if (pUINode) { pNotify->OnValueChanged(this, eAttribute, pUINode, pUINode->GetNodeItem(XFA_NODEITEM_Parent)); } break; } case XFA_Element::CheckButton: { bNeedFindContainer = true; CXFA_Node* pUINode = GetNodeItem(XFA_NODEITEM_Parent); if (pUINode) { pNotify->OnValueChanged(this, eAttribute, pUINode, pUINode->GetNodeItem(XFA_NODEITEM_Parent)); } break; } case XFA_Element::Keep: case XFA_Element::Bookend: case XFA_Element::Break: case XFA_Element::BreakAfter: case XFA_Element::BreakBefore: case XFA_Element::Overflow: bNeedFindContainer = true; break; case XFA_Element::Area: case XFA_Element::Draw: case XFA_Element::ExclGroup: case XFA_Element::Field: case XFA_Element::Subform: case XFA_Element::SubformSet: pLayoutPro->AddChangedContainer(this); pNotify->OnValueChanged(this, eAttribute, this, this); break; case XFA_Element::Sharptext: case XFA_Element::Sharpxml: case XFA_Element::SharpxHTML: { CXFA_Node* pTextNode = GetNodeItem(XFA_NODEITEM_Parent); if (!pTextNode) return; CXFA_Node* pValueNode = pTextNode->GetNodeItem(XFA_NODEITEM_Parent); if (!pValueNode) return; XFA_Element eType = pValueNode->GetElementType(); if (eType == XFA_Element::Value) { bNeedFindContainer = true; CXFA_Node* pNode = pValueNode->GetNodeItem(XFA_NODEITEM_Parent); if (pNode && pNode->IsContainerNode()) { if (bScriptModify) pValueNode = pNode; pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode); } else { pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetNodeItem(XFA_NODEITEM_Parent)); } } else { if (eType == XFA_Element::Items) { CXFA_Node* pNode = pValueNode->GetNodeItem(XFA_NODEITEM_Parent); if (pNode && pNode->IsContainerNode()) { pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode); } } } break; } default: break; } if (!bNeedFindContainer) return; CXFA_Node* pParent = this; while (pParent && !pParent->IsContainerNode()) pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent); if (pParent) pLayoutPro->AddChangedContainer(pParent); } void CXFA_Node::SyncValue(const WideString& wsValue, bool bNotify) { WideString wsFormatValue = wsValue; CXFA_WidgetAcc* pContainerWidgetAcc = GetContainerWidgetAcc(); if (pContainerWidgetAcc) wsFormatValue = pContainerWidgetAcc->GetFormatDataValue(wsValue); JSObject()->SetContent(wsValue, wsFormatValue, bNotify, false, true); }