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