xref: /aosp_15_r20/external/pdfium/xfa/fxfa/parser/cxfa_document.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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_document.h"
8 
9 #include <set>
10 #include <utility>
11 
12 #include "core/fxcrt/fx_extension.h"
13 #include "core/fxcrt/stl_util.h"
14 #include "core/fxcrt/xml/cfx_xmldocument.h"
15 #include "core/fxcrt/xml/cfx_xmlelement.h"
16 #include "fxjs/gc/container_trace.h"
17 #include "fxjs/xfa/cfxjse_engine.h"
18 #include "fxjs/xfa/cfxjse_resolveprocessor.h"
19 #include "fxjs/xfa/cjx_object.h"
20 #include "third_party/base/check.h"
21 #include "third_party/base/check_op.h"
22 #include "third_party/base/notreached.h"
23 #include "xfa/fxfa/cxfa_ffdoc.h"
24 #include "xfa/fxfa/cxfa_ffnotify.h"
25 #include "xfa/fxfa/parser/cscript_datawindow.h"
26 #include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
27 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
28 #include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
29 #include "xfa/fxfa/parser/cscript_logpseudomodel.h"
30 #include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
31 #include "xfa/fxfa/parser/cxfa_bind.h"
32 #include "xfa/fxfa/parser/cxfa_datagroup.h"
33 #include "xfa/fxfa/parser/cxfa_exdata.h"
34 #include "xfa/fxfa/parser/cxfa_form.h"
35 #include "xfa/fxfa/parser/cxfa_image.h"
36 #include "xfa/fxfa/parser/cxfa_interactive.h"
37 #include "xfa/fxfa/parser/cxfa_items.h"
38 #include "xfa/fxfa/parser/cxfa_localemgr.h"
39 #include "xfa/fxfa/parser/cxfa_node.h"
40 #include "xfa/fxfa/parser/cxfa_occur.h"
41 #include "xfa/fxfa/parser/cxfa_pageset.h"
42 #include "xfa/fxfa/parser/cxfa_pdf.h"
43 #include "xfa/fxfa/parser/cxfa_present.h"
44 #include "xfa/fxfa/parser/cxfa_subform.h"
45 #include "xfa/fxfa/parser/cxfa_template.h"
46 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
47 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
48 #include "xfa/fxfa/parser/cxfa_value.h"
49 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
50 #include "xfa/fxfa/parser/xfa_utils.h"
51 
52 namespace {
53 
54 const wchar_t kTemplateNS[] = L"http://www.xfa.org/schema/xfa-template/";
55 
56 struct RecurseRecord {
57   cppgc::Persistent<CXFA_Node> pTemplateChild;
58   cppgc::Persistent<CXFA_Node> pDataChild;
59 };
60 
61 class CXFA_TraverseStrategy_DDGroup {
62  public:
GetFirstChild(CXFA_Node * pDDGroupNode)63   static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
64     return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
65   }
GetNextSibling(CXFA_Node * pDDGroupNode)66   static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
67     return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
68   }
GetParent(CXFA_Node * pDDGroupNode)69   static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
70     return pDDGroupNode->GetParent();
71   }
72 };
73 
FormValueNode_MatchNoneCreateChild(CXFA_Node * pFormNode)74 void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
75   DCHECK(pFormNode->IsWidgetReady());
76   // GetUIChildNode has the side effect of creating the UI child.
77   pFormNode->GetUIChildNode();
78 }
79 
FormValueNode_CreateChild(CXFA_Node * pValueNode,XFA_Element iType)80 CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
81   CXFA_Node* pChildNode = pValueNode->GetFirstChild();
82   if (!pChildNode) {
83     if (iType == XFA_Element::Unknown)
84       return nullptr;
85 
86     pChildNode =
87         pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
88   }
89   return pChildNode;
90 }
91 
FormValueNode_SetChildContent(CXFA_Node * pValueNode,const WideString & wsContent,XFA_Element iType)92 void FormValueNode_SetChildContent(CXFA_Node* pValueNode,
93                                    const WideString& wsContent,
94                                    XFA_Element iType) {
95   if (!pValueNode)
96     return;
97 
98   DCHECK_EQ(pValueNode->GetPacketType(), XFA_PacketType::Form);
99   CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
100   if (!pChildNode)
101     return;
102 
103   switch (pChildNode->GetObjectType()) {
104     case XFA_ObjectType::ContentNode: {
105       CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
106       if (!pContentRawDataNode) {
107         XFA_Element element = XFA_Element::Sharptext;
108         if (pChildNode->GetElementType() == XFA_Element::ExData) {
109           absl::optional<WideString> contentType =
110               pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
111                                                    false);
112           if (contentType.has_value()) {
113             if (contentType.value().EqualsASCII("text/html"))
114               element = XFA_Element::SharpxHTML;
115             else if (contentType.value().EqualsASCII("text/xml"))
116               element = XFA_Element::Sharpxml;
117           }
118         }
119         pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
120         pChildNode->InsertChildAndNotify(pContentRawDataNode, nullptr);
121       }
122       pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value,
123                                                 wsContent);
124       break;
125     }
126     case XFA_ObjectType::NodeC:
127     case XFA_ObjectType::TextNode:
128     case XFA_ObjectType::NodeV: {
129       pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent);
130       break;
131     }
132     default:
133       break;
134   }
135 }
136 
MergeNodeRecurse(CXFA_Node * pDestNodeParent,CXFA_Node * pProtoNode)137 void MergeNodeRecurse(CXFA_Node* pDestNodeParent, CXFA_Node* pProtoNode) {
138   CXFA_Node* pExistingNode = nullptr;
139   for (CXFA_Node* pFormChild = pDestNodeParent->GetFirstChild(); pFormChild;
140        pFormChild = pFormChild->GetNextSibling()) {
141     if (pFormChild->GetElementType() == pProtoNode->GetElementType() &&
142         pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
143         pFormChild->IsUnusedNode()) {
144       pFormChild->ClearFlag(XFA_NodeFlag::kUnusedNode);
145       pExistingNode = pFormChild;
146       break;
147     }
148   }
149 
150   if (pExistingNode) {
151     pExistingNode->SetTemplateNode(pProtoNode);
152     for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild();
153          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
154       MergeNodeRecurse(pExistingNode, pTemplateChild);
155     }
156     return;
157   }
158   CXFA_Node* pNewNode = pProtoNode->Clone(true);
159   pNewNode->SetTemplateNode(pProtoNode);
160   pDestNodeParent->InsertChildAndNotify(pNewNode, nullptr);
161 }
162 
MergeNode(CXFA_Node * pDestNode,CXFA_Node * pProtoNode)163 void MergeNode(CXFA_Node* pDestNode, CXFA_Node* pProtoNode) {
164   {
165     CXFA_NodeIterator sIterator(pDestNode);
166     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
167          pNode = sIterator.MoveToNext()) {
168       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
169     }
170   }
171   pDestNode->SetTemplateNode(pProtoNode);
172   for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild(); pTemplateChild;
173        pTemplateChild = pTemplateChild->GetNextSibling()) {
174     MergeNodeRecurse(pDestNode, pTemplateChild);
175   }
176   {
177     CXFA_NodeIterator sIterator(pDestNode);
178     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
179          pNode = sIterator.MoveToNext()) {
180       pNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
181     }
182   }
183 }
184 
CloneOrMergeInstanceManager(CXFA_Document * pDocument,CXFA_Node * pFormParent,CXFA_Node * pTemplateNode,std::vector<CXFA_Node * > * subforms)185 CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
186                                        CXFA_Node* pFormParent,
187                                        CXFA_Node* pTemplateNode,
188                                        std::vector<CXFA_Node*>* subforms) {
189   WideString wsSubformName =
190       pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
191   WideString wsInstMgrNodeName = L"_" + wsSubformName;
192   uint32_t dwInstNameHash = FX_HashCode_GetW(wsInstMgrNodeName.AsStringView());
193   CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
194       pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
195   if (pExistingNode) {
196     uint32_t dwNameHash = pTemplateNode->GetNameHash();
197     for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
198       XFA_Element eCurType = pNode->GetElementType();
199       if (eCurType == XFA_Element::InstanceManager)
200         break;
201 
202       if ((eCurType != XFA_Element::Subform) &&
203           (eCurType != XFA_Element::SubformSet)) {
204         pNode = pNode->GetNextSibling();
205         continue;
206       }
207       if (dwNameHash != pNode->GetNameHash())
208         break;
209 
210       CXFA_Node* pNextNode = pNode->GetNextSibling();
211       pFormParent->RemoveChildAndNotify(pNode, true);
212       subforms->push_back(pNode);
213       pNode = pNextNode;
214     }
215     pFormParent->RemoveChildAndNotify(pExistingNode, true);
216     pFormParent->InsertChildAndNotify(pExistingNode, nullptr);
217     pExistingNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
218     pExistingNode->SetTemplateNode(pTemplateNode);
219     return pExistingNode;
220   }
221 
222   CXFA_Node* pNewNode =
223       pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
224   wsInstMgrNodeName =
225       L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
226   pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName);
227   pFormParent->InsertChildAndNotify(pNewNode, nullptr);
228   pNewNode->SetTemplateNode(pTemplateNode);
229   return pNewNode;
230 }
231 
SortRecurseRecord(std::vector<RecurseRecord> * rgRecords,CXFA_Node * pDataScope,bool bChoiceMode)232 void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
233                        CXFA_Node* pDataScope,
234                        bool bChoiceMode) {
235   std::vector<RecurseRecord> rgResultRecord;
236   for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
237        pNode = pNode->GetNextSibling()) {
238     auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
239                            [pNode](const RecurseRecord& record) {
240                              return pNode == record.pDataChild;
241                            });
242     if (it != rgRecords->end()) {
243       rgResultRecord.push_back(*it);
244       rgRecords->erase(it);
245       if (bChoiceMode)
246         break;
247     }
248   }
249   if (rgResultRecord.empty())
250     return;
251 
252   if (!bChoiceMode) {
253     rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
254                           rgRecords->end());
255   }
256   *rgRecords = rgResultRecord;
257 }
258 
ScopeMatchGlobalBinding(CXFA_Node * pDataScope,uint32_t dwNameHash,XFA_Element eMatchDataNodeType,bool bUpLevel)259 CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
260                                    uint32_t dwNameHash,
261                                    XFA_Element eMatchDataNodeType,
262                                    bool bUpLevel) {
263   for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
264        pCurDataScope &&
265        pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
266        pLastDataScope = pCurDataScope,
267                  pCurDataScope = pCurDataScope->GetParent()) {
268     for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
269          pDataChild;
270          pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
271       if (pDataChild == pLastDataScope ||
272           (eMatchDataNodeType != XFA_Element::DataModel &&
273            pDataChild->GetElementType() != eMatchDataNodeType) ||
274           pDataChild->HasBindItem()) {
275         continue;
276       }
277       return pDataChild;
278     }
279 
280     for (CXFA_DataGroup* pDataChild =
281              pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
282                  XFA_Element::DataGroup);
283          pDataChild;
284          pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
285              XFA_Element::DataGroup)) {
286       CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
287                                                      eMatchDataNodeType, false);
288       if (pDataNode)
289         return pDataNode;
290     }
291     if (!bUpLevel)
292       break;
293   }
294   return nullptr;
295 }
296 
FindGlobalDataNode(CXFA_Document * pDocument,const WideString & wsName,CXFA_Node * pDataScope,XFA_Element eMatchNodeType)297 CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
298                               const WideString& wsName,
299                               CXFA_Node* pDataScope,
300                               XFA_Element eMatchNodeType) {
301   if (wsName.IsEmpty())
302     return nullptr;
303 
304   uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView());
305   CXFA_Node* pBounded = pDocument->GetGlobalBinding(dwNameHash);
306   if (!pBounded) {
307     pBounded =
308         ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
309     if (pBounded)
310       pDocument->RegisterGlobalBinding(dwNameHash, pBounded);
311   }
312   return pBounded;
313 }
314 
FindOnceDataNode(const WideString & wsName,CXFA_Node * pDataScope,XFA_Element eMatchNodeType)315 CXFA_Node* FindOnceDataNode(const WideString& wsName,
316                             CXFA_Node* pDataScope,
317                             XFA_Element eMatchNodeType) {
318   if (wsName.IsEmpty())
319     return nullptr;
320 
321   uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView());
322   CXFA_Node* pLastDataScope = nullptr;
323   for (CXFA_Node* pCurDataScope = pDataScope;
324        pCurDataScope &&
325        pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
326        pCurDataScope = pCurDataScope->GetParent()) {
327     for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
328          pDataChild;
329          pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
330       if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
331           (eMatchNodeType != XFA_Element::DataModel &&
332            pDataChild->GetElementType() != eMatchNodeType)) {
333         continue;
334       }
335       return pDataChild;
336     }
337     pLastDataScope = pCurDataScope;
338   }
339   return nullptr;
340 }
341 
FindDataRefDataNode(CXFA_Document * pDocument,const WideString & wsRef,CXFA_Node * pDataScope,XFA_Element eMatchNodeType,CXFA_Node * pTemplateNode,bool bForceBind,bool bUpLevel)342 CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
343                                const WideString& wsRef,
344                                CXFA_Node* pDataScope,
345                                XFA_Element eMatchNodeType,
346                                CXFA_Node* pTemplateNode,
347                                bool bForceBind,
348                                bool bUpLevel) {
349   Mask<XFA_ResolveFlag> dwFlags = {XFA_ResolveFlag::kChildren,
350                                    XFA_ResolveFlag::kBindNew};
351   if (bUpLevel || !wsRef.EqualsASCII("name")) {
352     dwFlags |= XFA_ResolveFlag::kParent;
353     dwFlags |= XFA_ResolveFlag::kSiblings;
354   }
355   absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
356       pDocument->GetScriptContext()->ResolveObjectsWithBindNode(
357           pDataScope, wsRef.AsStringView(), dwFlags, pTemplateNode);
358   if (!maybeResult.has_value())
359     return nullptr;
360 
361   if (maybeResult.value().type ==
362           CFXJSE_Engine::ResolveResult::Type::kCreateNodeAll ||
363       maybeResult.value().type ==
364           CFXJSE_Engine::ResolveResult::Type::kCreateNodeMidAll ||
365       maybeResult.value().objects.size() > 1) {
366     return pDocument->GetNotBindNode(maybeResult.value().objects);
367   }
368 
369   if (maybeResult.value().type ==
370       CFXJSE_Engine::ResolveResult::Type::kCreateNodeOne) {
371     CXFA_Object* pObject = !maybeResult.value().objects.empty()
372                                ? maybeResult.value().objects.front().Get()
373                                : nullptr;
374     CXFA_Node* pNode = ToNode(pObject);
375     return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
376   }
377   return nullptr;
378 }
379 
FindMatchingDataNode(CXFA_Document * pDocument,CXFA_Node * pTemplateNode,CXFA_Node * pDataScope,bool & bAccessedDataDOM,bool bForceBind,CXFA_NodeIteratorTemplate<CXFA_Node,CXFA_TraverseStrategy_XFAContainerNode> * pIterator,bool & bSelfMatch,XFA_AttributeValue & eBindMatch,bool bUpLevel)380 CXFA_Node* FindMatchingDataNode(
381     CXFA_Document* pDocument,
382     CXFA_Node* pTemplateNode,
383     CXFA_Node* pDataScope,
384     bool& bAccessedDataDOM,
385     bool bForceBind,
386     CXFA_NodeIteratorTemplate<CXFA_Node,
387                               CXFA_TraverseStrategy_XFAContainerNode>*
388         pIterator,
389     bool& bSelfMatch,
390     XFA_AttributeValue& eBindMatch,
391     bool bUpLevel) {
392   CXFA_Node* pResult = nullptr;
393   CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
394   while (pCurTemplateNode) {
395     XFA_Element eMatchNodeType;
396     switch (pCurTemplateNode->GetElementType()) {
397       case XFA_Element::Subform:
398         eMatchNodeType = XFA_Element::DataGroup;
399         break;
400       case XFA_Element::Field: {
401         eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
402                              ? XFA_Element::DataGroup
403                              : XFA_Element::DataValue;
404       } break;
405       case XFA_Element::ExclGroup:
406         eMatchNodeType = XFA_Element::DataValue;
407         break;
408       default:
409         pCurTemplateNode = pIterator->MoveToNext();
410         continue;
411     }
412 
413     CXFA_Occur* pTemplateNodeOccur =
414         pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
415     if (pTemplateNodeOccur) {
416       int32_t iMin;
417       int32_t iMax;
418       int32_t iInit;
419       std::tie(iMin, iMax, iInit) = pTemplateNodeOccur->GetOccurInfo();
420       if (iMax == 0) {
421         pCurTemplateNode = pIterator->MoveToNext();
422         continue;
423       }
424     }
425 
426     CXFA_Bind* pTemplateNodeBind =
427         pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
428     XFA_AttributeValue eMatch =
429         pTemplateNodeBind
430             ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
431             : XFA_AttributeValue::Once;
432     eBindMatch = eMatch;
433     switch (eMatch) {
434       case XFA_AttributeValue::None:
435         pCurTemplateNode = pIterator->MoveToNext();
436         continue;
437       case XFA_AttributeValue::Global:
438         bAccessedDataDOM = true;
439         if (!bForceBind) {
440           pCurTemplateNode = pIterator->MoveToNext();
441           continue;
442         }
443         if (eMatchNodeType == XFA_Element::DataValue ||
444             (eMatchNodeType == XFA_Element::DataGroup &&
445              XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
446           CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
447               pDocument,
448               pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
449               pDataScope, eMatchNodeType);
450           if (!pGlobalBindNode) {
451             pCurTemplateNode = pIterator->MoveToNext();
452             continue;
453           }
454           pResult = pGlobalBindNode;
455           break;
456         }
457         [[fallthrough]];
458       case XFA_AttributeValue::Once: {
459         bAccessedDataDOM = true;
460         CXFA_Node* pOnceBindNode = FindOnceDataNode(
461             pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
462             pDataScope, eMatchNodeType);
463         if (!pOnceBindNode) {
464           pCurTemplateNode = pIterator->MoveToNext();
465           continue;
466         }
467         pResult = pOnceBindNode;
468         break;
469       }
470       case XFA_AttributeValue::DataRef: {
471         bAccessedDataDOM = true;
472         CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
473             pDocument,
474             pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
475             pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
476         if (pDataRefBindNode &&
477             pDataRefBindNode->GetElementType() == eMatchNodeType) {
478           pResult = pDataRefBindNode;
479         }
480         if (!pResult) {
481           pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
482           continue;
483         }
484         break;
485       }
486       default:
487         break;
488     }
489     if (pCurTemplateNode == pTemplateNode && pResult)
490       bSelfMatch = true;
491     break;
492   }
493   return pResult;
494 }
495 
CreateDataBinding(CXFA_Node * pFormNode,CXFA_Node * pDataNode,bool bDataToForm)496 void CreateDataBinding(CXFA_Node* pFormNode,
497                        CXFA_Node* pDataNode,
498                        bool bDataToForm) {
499   pFormNode->SetBindingNode(pDataNode);
500   pDataNode->AddBindItem(pFormNode);
501   XFA_Element eType = pFormNode->GetElementType();
502   if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
503     return;
504 
505   DCHECK(pFormNode->IsWidgetReady());
506   auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
507       0, XFA_Element::Value);
508   if (!bDataToForm) {
509     WideString wsValue;
510     switch (pFormNode->GetFFWidgetType()) {
511       case XFA_FFWidgetType::kImageEdit: {
512         CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
513         WideString wsContentType;
514         WideString wsHref;
515         if (image) {
516           wsValue = image->GetContent();
517           wsContentType = image->GetContentType();
518           wsHref = image->GetHref();
519         }
520         CFX_XMLElement* pXMLDataElement =
521             ToXMLElement(pDataNode->GetXMLMappingNode());
522         DCHECK(pXMLDataElement);
523         pDataNode->JSObject()->SetAttributeValue(
524             wsValue, pFormNode->GetFormatDataValue(wsValue));
525         pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
526                                         wsContentType);
527         if (!wsHref.IsEmpty())
528           pXMLDataElement->SetAttribute(L"href", wsHref);
529 
530         break;
531       }
532       case XFA_FFWidgetType::kChoiceList:
533         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
534         if (pFormNode->IsChoiceListMultiSelect()) {
535           std::vector<WideString> wsSelTextArray =
536               pFormNode->GetSelectedItemsValue();
537           if (!wsSelTextArray.empty()) {
538             for (const auto& text : wsSelTextArray) {
539               CXFA_Node* pValue =
540                   pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
541               pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value");
542               pValue->CreateXMLMappingNode();
543               pDataNode->InsertChildAndNotify(pValue, nullptr);
544               pValue->JSObject()->SetCData(XFA_Attribute::Value, text);
545             }
546           } else {
547             CFX_XMLElement* pElement =
548                 ToXMLElement(pDataNode->GetXMLMappingNode());
549             pElement->SetAttribute(L"xfa:dataNode", L"dataGroup");
550           }
551         } else if (!wsValue.IsEmpty()) {
552           pDataNode->JSObject()->SetAttributeValue(
553               wsValue, pFormNode->GetFormatDataValue(wsValue));
554         }
555         break;
556       case XFA_FFWidgetType::kCheckButton:
557         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
558         if (wsValue.IsEmpty())
559           break;
560 
561         pDataNode->JSObject()->SetAttributeValue(
562             wsValue, pFormNode->GetFormatDataValue(wsValue));
563         break;
564       case XFA_FFWidgetType::kExclGroup: {
565         CXFA_Node* pChecked = nullptr;
566         CXFA_Node* pChild = pFormNode->GetFirstChild();
567         for (; pChild; pChild = pChild->GetNextSibling()) {
568           if (pChild->GetElementType() != XFA_Element::Field)
569             continue;
570 
571           auto* pValue =
572               pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
573           if (!pValue)
574             continue;
575 
576           wsValue = pValue->GetChildValueContent();
577           if (wsValue.IsEmpty())
578             continue;
579 
580           CXFA_Items* pItems =
581               pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
582           if (!pItems)
583             continue;
584 
585           CXFA_Node* pText = pItems->GetFirstChild();
586           if (!pText)
587             continue;
588 
589           WideString wsContent = pText->JSObject()->GetContent(false);
590           if (wsContent == wsValue) {
591             pChecked = pChild;
592             pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue);
593             pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent);
594             break;
595           }
596         }
597         if (!pChecked)
598           break;
599 
600         pChild = pFormNode->GetFirstChild();
601         for (; pChild; pChild = pChild->GetNextSibling()) {
602           if (pChild == pChecked)
603             continue;
604           if (pChild->GetElementType() != XFA_Element::Field)
605             continue;
606 
607           CXFA_Value* pValue =
608               pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
609                   0, XFA_Element::Value);
610           CXFA_Items* pItems =
611               pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
612           CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
613           if (pText)
614             pText = pText->GetNextSibling();
615 
616           WideString wsContent;
617           if (pText)
618             wsContent = pText->JSObject()->GetContent(false);
619 
620           FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
621         }
622         break;
623       }
624       case XFA_FFWidgetType::kNumericEdit: {
625         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
626         if (wsValue.IsEmpty())
627           break;
628 
629         wsValue = pFormNode->NormalizeNumStr(wsValue);
630         pDataNode->JSObject()->SetAttributeValue(
631             wsValue, pFormNode->GetFormatDataValue(wsValue));
632         CXFA_Value* pValue =
633             pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
634                 0, XFA_Element::Value);
635         FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
636         break;
637       }
638       default:
639         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
640         if (wsValue.IsEmpty())
641           break;
642 
643         pDataNode->JSObject()->SetAttributeValue(
644             wsValue, pFormNode->GetFormatDataValue(wsValue));
645         break;
646     }
647     return;
648   }
649 
650   WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
651   WideString wsNormalizeValue = pFormNode->GetNormalizeDataValue(wsXMLValue);
652 
653   pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue);
654   switch (pFormNode->GetFFWidgetType()) {
655     case XFA_FFWidgetType::kImageEdit: {
656       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
657                                     XFA_Element::Image);
658       CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
659       if (image) {
660         CFX_XMLElement* pXMLDataElement =
661             ToXMLElement(pDataNode->GetXMLMappingNode());
662         WideString wsContentType =
663             pXMLDataElement->GetAttribute(L"xfa:contentType");
664         if (!wsContentType.IsEmpty()) {
665           pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
666                                           wsContentType);
667           image->SetContentType(wsContentType);
668         }
669 
670         WideString wsHref = pXMLDataElement->GetAttribute(L"href");
671         if (!wsHref.IsEmpty())
672           image->SetHref(wsHref);
673       }
674       break;
675     }
676     case XFA_FFWidgetType::kChoiceList:
677       if (pFormNode->IsChoiceListMultiSelect()) {
678         std::vector<CXFA_Node*> items = pDataNode->GetNodeListWithFilter(
679             {XFA_NodeFilter::kChildren, XFA_NodeFilter::kProperties});
680         if (!items.empty()) {
681           bool single = items.size() == 1;
682           wsNormalizeValue.clear();
683 
684           for (CXFA_Node* pNode : items) {
685             WideString wsItem = pNode->JSObject()->GetContent(false);
686             if (single)
687               wsItem += L"\n";
688 
689             wsNormalizeValue += wsItem;
690           }
691           CXFA_ExData* exData =
692               defValue ? defValue->GetExDataIfExists() : nullptr;
693           if (exData)
694             exData->SetContentType(single ? L"text/plain" : L"text/xml");
695         }
696         FormValueNode_SetChildContent(defValue, wsNormalizeValue,
697                                       XFA_Element::ExData);
698       } else {
699         FormValueNode_SetChildContent(defValue, wsNormalizeValue,
700                                       XFA_Element::Text);
701       }
702       break;
703     case XFA_FFWidgetType::kExclGroup: {
704       pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
705                                           false, false, false);
706       break;
707     }
708     case XFA_FFWidgetType::kDateTimeEdit:
709       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
710                                     XFA_Element::DateTime);
711       break;
712     case XFA_FFWidgetType::kNumericEdit: {
713       WideString wsPicture =
714           pFormNode->GetPictureContent(XFA_ValuePicture::kDataBind);
715       if (wsPicture.IsEmpty())
716         wsNormalizeValue = pFormNode->NormalizeNumStr(wsNormalizeValue);
717 
718       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
719                                     XFA_Element::Float);
720       break;
721     }
722     default:
723       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
724                                     XFA_Element::Text);
725       break;
726   }
727 }
728 
MaybeCreateDataNode(CXFA_Document * pDocument,CXFA_Node * pDataParent,XFA_Element eNodeType,const WideString & wsName)729 CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
730                                CXFA_Node* pDataParent,
731                                XFA_Element eNodeType,
732                                const WideString& wsName) {
733   if (!pDataParent)
734     return nullptr;
735 
736   CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
737   if (!pParentDDNode) {
738     CXFA_Node* pDataNode =
739         pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
740     pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName);
741     pDataNode->CreateXMLMappingNode();
742     pDataParent->InsertChildAndNotify(pDataNode, nullptr);
743     pDataNode->SetFlag(XFA_NodeFlag::kInitialized);
744     return pDataNode;
745   }
746 
747   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
748       pParentDDNode);
749   for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
750        pDDGroupNode = sIterator.MoveToNext()) {
751     if (pDDGroupNode != pParentDDNode) {
752       if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
753         continue;
754 
755       absl::optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
756       if (!ns.has_value() ||
757           !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
758         continue;
759       }
760     }
761 
762     CXFA_Node* pDDNode =
763         pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
764     if (!pDDNode)
765       continue;
766     if (pDDNode->GetElementType() != eNodeType)
767       break;
768 
769     CXFA_Node* pDataNode =
770         pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
771     pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName);
772     pDataNode->CreateXMLMappingNode();
773     if (eNodeType == XFA_Element::DataValue &&
774         pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
775             XFA_AttributeValue::MetaData) {
776       pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
777                                      XFA_AttributeValue::MetaData, false);
778     }
779     pDataParent->InsertChildAndNotify(pDataNode, nullptr);
780     pDataNode->SetDataDescriptionNode(pDDNode);
781     pDataNode->SetFlag(XFA_NodeFlag::kInitialized);
782     return pDataNode;
783   }
784   return nullptr;
785 }
786 
CopyContainer_Field(CXFA_Document * pDocument,CXFA_Node * pTemplateNode,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bDataMerge,bool bUpLevel)787 CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
788                                CXFA_Node* pTemplateNode,
789                                CXFA_Node* pFormNode,
790                                CXFA_Node* pDataScope,
791                                bool bDataMerge,
792                                bool bUpLevel) {
793   CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
794       pDocument, pFormNode, pTemplateNode, false, nullptr);
795   DCHECK(pFieldNode);
796   for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
797        pTemplateChildNode;
798        pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
799     if (XFA_DataMerge_NeedGenerateForm(pTemplateChildNode, true)) {
800       XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
801                                           pTemplateChildNode, true, nullptr);
802     } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
803                pTemplateChildNode->IsContainerNode()) {
804       if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
805         CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
806                             false, true);
807       }
808     }
809   }
810   if (bDataMerge) {
811     bool bAccessedDataDOM = false;
812     bool bSelfMatch = false;
813     XFA_AttributeValue eBindMatch;
814     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
815         sNodeIter(pTemplateNode);
816     CXFA_Node* pDataNode = FindMatchingDataNode(
817         pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
818         &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
819     if (pDataNode)
820       CreateDataBinding(pFieldNode, pDataNode, true);
821   } else {
822     FormValueNode_MatchNoneCreateChild(pFieldNode);
823   }
824   return pFieldNode;
825 }
826 
CopyContainer_SubformSet(CXFA_Document * pDocument,CXFA_Node * pTemplateNode,CXFA_Node * pFormParentNode,CXFA_Node * pDataScope,bool bOneInstance,bool bDataMerge)827 CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
828                                     CXFA_Node* pTemplateNode,
829                                     CXFA_Node* pFormParentNode,
830                                     CXFA_Node* pDataScope,
831                                     bool bOneInstance,
832                                     bool bDataMerge) {
833   XFA_Element eType = pTemplateNode->GetElementType();
834   CXFA_Node* pOccurNode = nullptr;
835   CXFA_Node* pFirstInstance = nullptr;
836   bool bUseInstanceManager =
837       pFormParentNode->GetElementType() != XFA_Element::Area;
838   CXFA_Node* pInstMgrNode = nullptr;
839   std::vector<CXFA_Node*> subformArray;
840   std::vector<CXFA_Node*>* pSearchArray = nullptr;
841   if (!bOneInstance &&
842       (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
843     pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
844                                              pDocument, pFormParentNode,
845                                              pTemplateNode, &subformArray)
846                                        : nullptr;
847     if (CXFA_Occur* pOccurTemplateNode =
848             pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
849                 XFA_Element::Occur)) {
850       pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
851                                       pDocument, pInstMgrNode,
852                                       pOccurTemplateNode, false, nullptr)
853                                 : pOccurTemplateNode;
854     } else if (pInstMgrNode) {
855       pOccurNode =
856           pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
857       if (pOccurNode)
858         pOccurNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
859     }
860     if (pInstMgrNode) {
861       pInstMgrNode->SetInitializedFlagAndNotify();
862       pSearchArray = &subformArray;
863       if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
864         bOneInstance = true;
865         if (subformArray.empty())
866           pSearchArray = nullptr;
867       } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
868         pSearchArray = nullptr;
869       }
870     }
871   }
872 
873   int32_t iMax = 1;
874   int32_t iInit = 1;
875   int32_t iMin = 1;
876   if (!bOneInstance && pOccurNode) {
877     std::tie(iMin, iMax, iInit) =
878         static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
879   }
880 
881   XFA_AttributeValue eRelation =
882       eType == XFA_Element::SubformSet
883           ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
884           : XFA_AttributeValue::Ordered;
885   int32_t iCurRepeatIndex = 0;
886   XFA_AttributeValue eParentBindMatch = XFA_AttributeValue::None;
887   if (bDataMerge) {
888     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
889         sNodeIterator(pTemplateNode);
890     bool bAccessedDataDOM = false;
891     if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
892       sNodeIterator.MoveToNext();
893     } else {
894       std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
895       std::vector<CXFA_Node*> nodeArray;
896       for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
897         bool bSelfMatch = false;
898         XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
899         CXFA_Node* pDataNode = FindMatchingDataNode(
900             pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
901             &sNodeIterator, bSelfMatch, eBindMatch, true);
902         if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
903           break;
904 
905         eParentBindMatch = eBindMatch;
906         CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
907             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
908         if (!pFirstInstance)
909           pFirstInstance = pSubformNode;
910 
911         CreateDataBinding(pSubformNode, pDataNode, true);
912         DCHECK(pSubformNode);
913         subformMapArray[pSubformNode] = pDataNode;
914         nodeArray.push_back(pSubformNode);
915       }
916 
917       for (CXFA_Node* pSubform : nodeArray) {
918         CXFA_Node* pDataNode = nullptr;
919         auto it = subformMapArray.find(pSubform);
920         if (it != subformMapArray.end())
921           pDataNode = it->second;
922         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
923              pTemplateChild;
924              pTemplateChild = pTemplateChild->GetNextSibling()) {
925           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
926                                              bUseInstanceManager)) {
927             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
928                                                 pTemplateChild, true, nullptr);
929           } else if (pTemplateChild->IsContainerNode()) {
930             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
931                                                pDataNode, false, true, false);
932           }
933         }
934       }
935       subformMapArray.clear();
936     }
937 
938     for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
939       bool bSelfMatch = false;
940       XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
941       if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
942                                 bAccessedDataDOM, false, &sNodeIterator,
943                                 bSelfMatch, eBindMatch, true)) {
944         break;
945       }
946       if (eBindMatch == XFA_AttributeValue::DataRef &&
947           eParentBindMatch == XFA_AttributeValue::DataRef) {
948         break;
949       }
950 
951       if (eRelation == XFA_AttributeValue::Choice ||
952           eRelation == XFA_AttributeValue::Unordered) {
953         CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
954             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
955         DCHECK(pSubformSetNode);
956         if (!pFirstInstance)
957           pFirstInstance = pSubformSetNode;
958 
959         std::vector<RecurseRecord> rgItemMatchList;
960         std::vector<CXFA_Node*> rgItemUnmatchList;
961         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
962              pTemplateChild;
963              pTemplateChild = pTemplateChild->GetNextSibling()) {
964           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
965                                              bUseInstanceManager)) {
966             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
967                                                 pTemplateChild, true, nullptr);
968           } else if (pTemplateChild->IsContainerNode()) {
969             bSelfMatch = false;
970             eBindMatch = XFA_AttributeValue::None;
971             if (eRelation != XFA_AttributeValue::Ordered) {
972               CXFA_NodeIteratorTemplate<CXFA_Node,
973                                         CXFA_TraverseStrategy_XFAContainerNode>
974                   sChildIter(pTemplateChild);
975               CXFA_Node* pDataMatch = FindMatchingDataNode(
976                   pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
977                   false, &sChildIter, bSelfMatch, eBindMatch, true);
978               if (pDataMatch) {
979                 RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
980                 if (bSelfMatch)
981                   rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
982                 else
983                   rgItemMatchList.push_back(sNewRecord);
984               } else {
985                 rgItemUnmatchList.push_back(pTemplateChild);
986               }
987             } else {
988               rgItemUnmatchList.push_back(pTemplateChild);
989             }
990           }
991         }
992 
993         switch (eRelation) {
994           case XFA_AttributeValue::Choice: {
995             DCHECK(!rgItemMatchList.empty());
996             SortRecurseRecord(&rgItemMatchList, pDataScope, true);
997             pDocument->DataMerge_CopyContainer(
998                 rgItemMatchList.front().pTemplateChild, pSubformSetNode,
999                 pDataScope, false, true, true);
1000             break;
1001           }
1002           case XFA_AttributeValue::Unordered: {
1003             if (!rgItemMatchList.empty()) {
1004               SortRecurseRecord(&rgItemMatchList, pDataScope, false);
1005               for (const auto& matched : rgItemMatchList) {
1006                 pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
1007                                                    pSubformSetNode, pDataScope,
1008                                                    false, true, true);
1009               }
1010             }
1011             for (auto* unmatched : rgItemUnmatchList) {
1012               pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
1013                                                  pDataScope, false, true, true);
1014             }
1015             break;
1016           }
1017           default:
1018             break;
1019         }
1020       } else {
1021         CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1022             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1023         DCHECK(pSubformSetNode);
1024         if (!pFirstInstance)
1025           pFirstInstance = pSubformSetNode;
1026 
1027         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1028              pTemplateChild;
1029              pTemplateChild = pTemplateChild->GetNextSibling()) {
1030           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
1031                                              bUseInstanceManager)) {
1032             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
1033                                                 pTemplateChild, true, nullptr);
1034           } else if (pTemplateChild->IsContainerNode()) {
1035             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
1036                                                pDataScope, false, true, true);
1037           }
1038         }
1039       }
1040     }
1041 
1042     if (iCurRepeatIndex == 0 && !bAccessedDataDOM) {
1043       int32_t iLimit = iMax;
1044       if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
1045         iLimit = fxcrt::CollectionSize<int32_t>(subformArray);
1046         if (iLimit < iMin)
1047           iLimit = iInit;
1048       }
1049 
1050       for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
1051         if (pInstMgrNode) {
1052           if (pSearchArray && pSearchArray->empty()) {
1053             if (pTemplateNode->GetNameHash() != 0)
1054               break;
1055             pSearchArray = nullptr;
1056           }
1057         } else if (!XFA_DataMerge_FindFormDOMInstance(
1058                        pDocument, pTemplateNode->GetElementType(),
1059                        pTemplateNode->GetNameHash(), pFormParentNode)) {
1060           break;
1061         }
1062         CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
1063             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1064         DCHECK(pSubformNode);
1065         if (!pFirstInstance)
1066           pFirstInstance = pSubformNode;
1067 
1068         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1069              pTemplateChild;
1070              pTemplateChild = pTemplateChild->GetNextSibling()) {
1071           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
1072                                              bUseInstanceManager)) {
1073             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
1074                                                 pTemplateChild, true, nullptr);
1075           } else if (pTemplateChild->IsContainerNode()) {
1076             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
1077                                                pDataScope, false, true, true);
1078           }
1079         }
1080       }
1081     }
1082   }
1083 
1084   int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
1085   for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
1086     CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1087         pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1088     DCHECK(pSubformSetNode);
1089     if (!pFirstInstance)
1090       pFirstInstance = pSubformSetNode;
1091 
1092     bool bFound = false;
1093     for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1094          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
1095       if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
1096         XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
1097                                             pTemplateChild, true, nullptr);
1098       } else if (pTemplateChild->IsContainerNode()) {
1099         if (bFound && eRelation == XFA_AttributeValue::Choice)
1100           continue;
1101 
1102         pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
1103                                            pDataScope, false, bDataMerge, true);
1104         bFound = true;
1105       }
1106     }
1107   }
1108   return pFirstInstance;
1109 }
1110 
UpdateBindingRelations(CXFA_Document * pDocument,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bDataRef,bool bParentDataRef)1111 void UpdateBindingRelations(CXFA_Document* pDocument,
1112                             CXFA_Node* pFormNode,
1113                             CXFA_Node* pDataScope,
1114                             bool bDataRef,
1115                             bool bParentDataRef) {
1116   bool bMatchRef = true;
1117   XFA_Element eType = pFormNode->GetElementType();
1118   CXFA_Node* pDataNode = pFormNode->GetBindData();
1119   if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
1120       eType == XFA_Element::Field) {
1121     CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
1122     CXFA_Bind* pTemplateNodeBind =
1123         pTemplateNode
1124             ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
1125             : nullptr;
1126     XFA_AttributeValue eMatch =
1127         pTemplateNodeBind
1128             ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
1129             : XFA_AttributeValue::Once;
1130     switch (eMatch) {
1131       case XFA_AttributeValue::None:
1132         if (!bDataRef || bParentDataRef)
1133           FormValueNode_MatchNoneCreateChild(pFormNode);
1134         break;
1135       case XFA_AttributeValue::Once:
1136         if (!bDataRef || bParentDataRef) {
1137           if (!pDataNode) {
1138             if (pFormNode->GetNameHash() != 0 &&
1139                 pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
1140                     XFA_AttributeValue::None) {
1141               XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
1142                                            XFA_FieldIsMultiListBox(pFormNode))
1143                                               ? XFA_Element::DataGroup
1144                                               : XFA_Element::DataValue;
1145               pDataNode = MaybeCreateDataNode(
1146                   pDocument, pDataScope, eDataNodeType,
1147                   WideString(
1148                       pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
1149               if (pDataNode)
1150                 CreateDataBinding(pFormNode, pDataNode, false);
1151             }
1152             if (!pDataNode)
1153               FormValueNode_MatchNoneCreateChild(pFormNode);
1154 
1155           } else {
1156             CXFA_Node* pDataParent = pDataNode->GetParent();
1157             if (pDataParent != pDataScope) {
1158               DCHECK(pDataParent);
1159               pDataParent->RemoveChildAndNotify(pDataNode, true);
1160               pDataScope->InsertChildAndNotify(pDataNode, nullptr);
1161             }
1162           }
1163         }
1164         break;
1165       case XFA_AttributeValue::Global:
1166         if (!bDataRef || bParentDataRef) {
1167           uint32_t dwNameHash = pFormNode->GetNameHash();
1168           if (dwNameHash != 0 && !pDataNode) {
1169             pDataNode = pDocument->GetGlobalBinding(dwNameHash);
1170             if (!pDataNode) {
1171               XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
1172                                            XFA_FieldIsMultiListBox(pFormNode))
1173                                               ? XFA_Element::DataGroup
1174                                               : XFA_Element::DataValue;
1175               CXFA_Node* pRecordNode =
1176                   ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
1177               pDataNode = MaybeCreateDataNode(
1178                   pDocument, pRecordNode, eDataNodeType,
1179                   WideString(
1180                       pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
1181               if (pDataNode) {
1182                 CreateDataBinding(pFormNode, pDataNode, false);
1183                 pDocument->RegisterGlobalBinding(pFormNode->GetNameHash(),
1184                                                  pDataNode);
1185               }
1186             } else {
1187               CreateDataBinding(pFormNode, pDataNode, true);
1188             }
1189           }
1190           if (!pDataNode)
1191             FormValueNode_MatchNoneCreateChild(pFormNode);
1192         }
1193         break;
1194       case XFA_AttributeValue::DataRef: {
1195         bMatchRef = bDataRef;
1196         bParentDataRef = true;
1197         if (!pDataNode && bDataRef) {
1198           WideString wsRef =
1199               pTemplateNodeBind
1200                   ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
1201                   : WideString();
1202           const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kChildren,
1203                                                 XFA_ResolveFlag::kCreateNode};
1204           absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1205               pDocument->GetScriptContext()->ResolveObjectsWithBindNode(
1206                   pDataScope, wsRef.AsStringView(), kFlags, pTemplateNode);
1207           CXFA_Object* pObject =
1208               maybeResult.has_value() && !maybeResult.value().objects.empty()
1209                   ? maybeResult.value().objects.front().Get()
1210                   : nullptr;
1211           pDataNode = ToNode(pObject);
1212           if (pDataNode) {
1213             CreateDataBinding(
1214                 pFormNode, pDataNode,
1215                 maybeResult.value().type ==
1216                     CFXJSE_Engine::ResolveResult::Type::kExistNodes);
1217           } else {
1218             FormValueNode_MatchNoneCreateChild(pFormNode);
1219           }
1220         }
1221         break;
1222       }
1223       default:
1224         break;
1225     }
1226   }
1227 
1228   if (bMatchRef &&
1229       (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
1230        eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
1231        eType == XFA_Element::PageSet)) {
1232     for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
1233          pFormChild = pFormChild->GetNextSibling()) {
1234       if (!pFormChild->IsContainerNode())
1235         continue;
1236       if (pFormChild->IsUnusedNode())
1237         continue;
1238 
1239       UpdateBindingRelations(pDocument, pFormChild,
1240                              pDataNode ? pDataNode : pDataScope, bDataRef,
1241                              bParentDataRef);
1242     }
1243   }
1244 }
1245 
UpdateDataRelation(CXFA_Node * pDataNode,CXFA_Node * pDataDescriptionNode)1246 void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
1247   DCHECK(pDataDescriptionNode);
1248   for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
1249        pDataChild = pDataChild->GetNextSibling()) {
1250     uint32_t dwNameHash = pDataChild->GetNameHash();
1251     if (!dwNameHash)
1252       continue;
1253 
1254     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
1255         sIterator(pDataDescriptionNode);
1256     for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
1257          pDDGroupNode = sIterator.MoveToNext()) {
1258       if (pDDGroupNode != pDataDescriptionNode) {
1259         if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
1260           continue;
1261 
1262         absl::optional<WideString> ns =
1263             pDDGroupNode->JSObject()->TryNamespace();
1264         if (!ns.has_value() ||
1265             !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
1266           continue;
1267         }
1268       }
1269 
1270       CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
1271       if (!pDDNode)
1272         continue;
1273       if (pDDNode->GetElementType() != pDataChild->GetElementType())
1274         break;
1275 
1276       pDataChild->SetDataDescriptionNode(pDDNode);
1277       UpdateDataRelation(pDataChild, pDDNode);
1278       break;
1279     }
1280   }
1281 }
1282 
1283 }  // namespace
1284 
CXFA_Document(CXFA_FFNotify * notify,cppgc::Heap * heap,LayoutProcessorIface * pLayout)1285 CXFA_Document::CXFA_Document(CXFA_FFNotify* notify,
1286                              cppgc::Heap* heap,
1287                              LayoutProcessorIface* pLayout)
1288     : heap_(heap),
1289       notify_(notify),
1290       node_owner_(cppgc::MakeGarbageCollected<CXFA_NodeOwner>(
1291           heap->GetAllocationHandle())),
1292       m_pLayoutProcessor(std::move(pLayout)) {
1293   if (m_pLayoutProcessor)
1294     m_pLayoutProcessor->SetDocument(this);
1295 }
1296 
1297 CXFA_Document::~CXFA_Document() = default;
1298 
Trace(cppgc::Visitor * visitor) const1299 void CXFA_Document::Trace(cppgc::Visitor* visitor) const {
1300   visitor->Trace(notify_);
1301   visitor->Trace(node_owner_);
1302   visitor->Trace(m_pRootNode);
1303   visitor->Trace(m_pLocaleMgr);
1304   visitor->Trace(m_pLayoutProcessor);
1305   visitor->Trace(m_pScriptDataWindow);
1306   visitor->Trace(m_pScriptEvent);
1307   visitor->Trace(m_pScriptHost);
1308   visitor->Trace(m_pScriptLog);
1309   visitor->Trace(m_pScriptLayout);
1310   visitor->Trace(m_pScriptSignature);
1311   ContainerTrace(visitor, m_rgGlobalBinding);
1312   ContainerTrace(visitor, m_pPendingPageSet);
1313 }
1314 
ClearLayoutData()1315 void CXFA_Document::ClearLayoutData() {
1316   m_pLayoutProcessor = nullptr;
1317   m_pScriptContext.reset();
1318   m_pLocaleMgr.Clear();
1319   m_pScriptDataWindow = nullptr;
1320   m_pScriptEvent = nullptr;
1321   m_pScriptHost = nullptr;
1322   m_pScriptLog = nullptr;
1323   m_pScriptLayout = nullptr;
1324   m_pScriptSignature = nullptr;
1325 }
1326 
GetXFAObject(XFA_HashCode dwNodeNameHash)1327 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
1328   switch (dwNodeNameHash) {
1329     case XFA_HASHCODE_Data: {
1330       CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
1331       if (!pDatasetsNode)
1332         return nullptr;
1333 
1334       for (CXFA_DataGroup* pDatasetsChild =
1335                pDatasetsNode->GetFirstChildByClass<CXFA_DataGroup>(
1336                    XFA_Element::DataGroup);
1337            pDatasetsChild;
1338            pDatasetsChild =
1339                pDatasetsChild->GetNextSameClassSibling<CXFA_DataGroup>(
1340                    XFA_Element::DataGroup)) {
1341         if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
1342           continue;
1343 
1344         absl::optional<WideString> namespaceURI =
1345             pDatasetsChild->JSObject()->TryNamespace();
1346         if (!namespaceURI.has_value())
1347           continue;
1348 
1349         absl::optional<WideString> datasetsURI =
1350             pDatasetsNode->JSObject()->TryNamespace();
1351         if (!datasetsURI.has_value())
1352           continue;
1353         if (namespaceURI.value() == datasetsURI.value())
1354           return pDatasetsChild;
1355       }
1356       return nullptr;
1357     }
1358     case XFA_HASHCODE_Record: {
1359       CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
1360       return pData ? pData->GetFirstChildByClass<CXFA_DataGroup>(
1361                          XFA_Element::DataGroup)
1362                    : nullptr;
1363     }
1364     case XFA_HASHCODE_DataWindow: {
1365       if (!m_pScriptDataWindow)
1366         m_pScriptDataWindow = cppgc::MakeGarbageCollected<CScript_DataWindow>(
1367             GetHeap()->GetAllocationHandle(), this);
1368       return m_pScriptDataWindow;
1369     }
1370     case XFA_HASHCODE_Event: {
1371       if (!m_pScriptEvent)
1372         m_pScriptEvent = cppgc::MakeGarbageCollected<CScript_EventPseudoModel>(
1373             GetHeap()->GetAllocationHandle(), this);
1374       return m_pScriptEvent;
1375     }
1376     case XFA_HASHCODE_Host: {
1377       if (!m_pScriptHost)
1378         m_pScriptHost = cppgc::MakeGarbageCollected<CScript_HostPseudoModel>(
1379             GetHeap()->GetAllocationHandle(), this);
1380       return m_pScriptHost;
1381     }
1382     case XFA_HASHCODE_Log: {
1383       if (!m_pScriptLog)
1384         m_pScriptLog = cppgc::MakeGarbageCollected<CScript_LogPseudoModel>(
1385             GetHeap()->GetAllocationHandle(), this);
1386       return m_pScriptLog;
1387     }
1388     case XFA_HASHCODE_Signature: {
1389       if (!m_pScriptSignature)
1390         m_pScriptSignature =
1391             cppgc::MakeGarbageCollected<CScript_SignaturePseudoModel>(
1392                 GetHeap()->GetAllocationHandle(), this);
1393       return m_pScriptSignature;
1394     }
1395     case XFA_HASHCODE_Layout: {
1396       if (!m_pScriptLayout)
1397         m_pScriptLayout =
1398             cppgc::MakeGarbageCollected<CScript_LayoutPseudoModel>(
1399                 GetHeap()->GetAllocationHandle(), this);
1400       return m_pScriptLayout;
1401     }
1402     default:
1403       return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
1404   }
1405 }
1406 
CreateNode(XFA_PacketType packet,XFA_Element eElement)1407 CXFA_Node* CXFA_Document::CreateNode(XFA_PacketType packet,
1408                                      XFA_Element eElement) {
1409   if (eElement == XFA_Element::Unknown)
1410     return nullptr;
1411 
1412   return CXFA_Node::Create(this, eElement, packet);
1413 }
1414 
IsInteractive()1415 bool CXFA_Document::IsInteractive() {
1416   if (m_Interactive.has_value())
1417     return m_Interactive.value();
1418 
1419   CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
1420   if (!pConfig)
1421     return false;
1422 
1423   CXFA_Present* pPresent =
1424       pConfig->GetFirstChildByClass<CXFA_Present>(XFA_Element::Present);
1425   if (!pPresent)
1426     return false;
1427 
1428   CXFA_Pdf* pPDF = pPresent->GetFirstChildByClass<CXFA_Pdf>(XFA_Element::Pdf);
1429   if (!pPDF)
1430     return false;
1431 
1432   CXFA_Interactive* pFormFiller =
1433       pPDF->GetChild<CXFA_Interactive>(0, XFA_Element::Interactive, false);
1434   if (!pFormFiller)
1435     return false;
1436 
1437   WideString wsInteractive = pFormFiller->JSObject()->GetContent(false);
1438   bool bInteractive = wsInteractive.EqualsASCII("1");
1439   m_Interactive = bInteractive;
1440   return bInteractive;
1441 }
1442 
GetLocaleMgr()1443 CXFA_LocaleMgr* CXFA_Document::GetLocaleMgr() {
1444   if (!m_pLocaleMgr) {
1445     m_pLocaleMgr = cppgc::MakeGarbageCollected<CXFA_LocaleMgr>(
1446         heap_->GetAllocationHandle(), heap_,
1447         ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
1448         GetNotify()->GetAppProvider()->GetLanguage());
1449   }
1450   return m_pLocaleMgr;
1451 }
1452 
GetHeap() const1453 cppgc::Heap* CXFA_Document::GetHeap() const {
1454   return heap_;
1455 }
1456 
InitScriptContext(CJS_Runtime * fxjs_runtime)1457 CFXJSE_Engine* CXFA_Document::InitScriptContext(CJS_Runtime* fxjs_runtime) {
1458   DCHECK(!m_pScriptContext);
1459   m_pScriptContext = std::make_unique<CFXJSE_Engine>(this, fxjs_runtime);
1460   return m_pScriptContext.get();
1461 }
1462 
GetScriptContext() const1463 CFXJSE_Engine* CXFA_Document::GetScriptContext() const {
1464   DCHECK(m_pScriptContext);
1465   return m_pScriptContext.get();
1466 }
1467 
RecognizeXFAVersionNumber(const WideString & wsTemplateNS)1468 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
1469     const WideString& wsTemplateNS) {
1470   XFA_VERSION eVersion = ParseXFAVersion(wsTemplateNS);
1471   if (eVersion != XFA_VERSION_UNKNOWN)
1472     m_eCurVersionMode = eVersion;
1473 
1474   return eVersion;
1475 }
1476 
1477 // static
ParseXFAVersion(const WideString & wsTemplateNS)1478 XFA_VERSION CXFA_Document::ParseXFAVersion(const WideString& wsTemplateNS) {
1479   WideStringView wsTemplateURIPrefix(kTemplateNS);
1480   if (wsTemplateNS.GetLength() <= wsTemplateURIPrefix.GetLength())
1481     return XFA_VERSION_UNKNOWN;
1482 
1483   size_t prefixLength = wsTemplateURIPrefix.GetLength();
1484   if (wsTemplateNS.AsStringView().First(prefixLength) != wsTemplateURIPrefix)
1485     return XFA_VERSION_UNKNOWN;
1486 
1487   auto nDotPos = wsTemplateNS.Find('.', prefixLength);
1488   if (!nDotPos.has_value())
1489     return XFA_VERSION_UNKNOWN;
1490 
1491   int8_t iMajor = FXSYS_wtoi(
1492       wsTemplateNS.Substr(prefixLength, nDotPos.value() - prefixLength)
1493           .c_str());
1494   int8_t iMinor = FXSYS_wtoi(wsTemplateNS.Substr(nDotPos.value() + 1).c_str());
1495   XFA_VERSION eVersion =
1496       static_cast<XFA_VERSION>(static_cast<int32_t>(iMajor) * 100 + iMinor);
1497   if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
1498     return XFA_VERSION_UNKNOWN;
1499 
1500   return eVersion;
1501 }
1502 
GetFormType() const1503 FormType CXFA_Document::GetFormType() const {
1504   return GetNotify()->GetFFDoc()->GetFormType();
1505 }
1506 
GetNodeByID(CXFA_Node * pRoot,WideStringView wsID) const1507 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
1508                                       WideStringView wsID) const {
1509   if (!pRoot || wsID.IsEmpty())
1510     return nullptr;
1511 
1512   CXFA_NodeIterator sIterator(pRoot);
1513   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1514        pNode = sIterator.MoveToNext()) {
1515     WideString wsIDVal = pNode->JSObject()->GetCData(XFA_Attribute::Id);
1516     if (!wsIDVal.IsEmpty() && wsIDVal == wsID)
1517       return pNode;
1518   }
1519   return nullptr;
1520 }
1521 
DoProtoMerge()1522 void CXFA_Document::DoProtoMerge() {
1523   CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
1524   if (!pTemplateRoot)
1525     return;
1526 
1527   std::map<uint32_t, CXFA_Node*> mIDMap;
1528   std::set<CXFA_Node*> sUseNodes;
1529   CXFA_NodeIterator sIterator(pTemplateRoot);
1530   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1531        pNode = sIterator.MoveToNext()) {
1532     WideString wsIDVal = pNode->JSObject()->GetCData(XFA_Attribute::Id);
1533     if (!wsIDVal.IsEmpty())
1534       mIDMap[FX_HashCode_GetW(wsIDVal.AsStringView())] = pNode;
1535 
1536     WideString wsUseVal = pNode->JSObject()->GetCData(XFA_Attribute::Use);
1537     if (!wsUseVal.IsEmpty()) {
1538       sUseNodes.insert(pNode);
1539     } else {
1540       wsUseVal = pNode->JSObject()->GetCData(XFA_Attribute::Usehref);
1541       if (!wsUseVal.IsEmpty())
1542         sUseNodes.insert(pNode);
1543     }
1544   }
1545 
1546   for (CXFA_Node* pUseHrefNode : sUseNodes) {
1547     // Must outlive the WideStringViews below.
1548     WideString wsUseVal =
1549         pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Usehref);
1550     WideStringView wsURI;
1551     WideStringView wsID;
1552     WideStringView wsSOM;
1553     if (!wsUseVal.IsEmpty()) {
1554       ParseUseHref(wsUseVal, wsURI, wsID, wsSOM);
1555       if (!wsURI.IsEmpty() && !wsURI.EqualsASCII("."))
1556         continue;
1557     } else {
1558       wsUseVal = pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Use);
1559       ParseUse(wsUseVal, wsID, wsSOM);
1560     }
1561 
1562     CXFA_Node* pProtoNode = nullptr;
1563     if (!wsSOM.IsEmpty()) {
1564       absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1565           m_pScriptContext->ResolveObjects(
1566               pUseHrefNode, wsSOM,
1567               Mask<XFA_ResolveFlag>{
1568                   XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
1569                   XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
1570                   XFA_ResolveFlag::kSiblings});
1571       if (maybeResult.has_value()) {
1572         auto* pFirstObject = maybeResult.value().objects.front().Get();
1573         if (pFirstObject && pFirstObject->IsNode())
1574           pProtoNode = pFirstObject->AsNode();
1575       }
1576     } else if (!wsID.IsEmpty()) {
1577       auto it = mIDMap.find(FX_HashCode_GetW(wsID));
1578       if (it == mIDMap.end())
1579         continue;
1580       pProtoNode = it->second;
1581     }
1582     if (!pProtoNode)
1583       continue;
1584 
1585     MergeNode(pUseHrefNode, pProtoNode);
1586   }
1587 }
1588 
1589 // static
ParseUseHref(const WideString & wsUseVal,WideStringView & wsURI,WideStringView & wsID,WideStringView & wsSOM)1590 void CXFA_Document::ParseUseHref(const WideString& wsUseVal,
1591                                  WideStringView& wsURI,
1592                                  WideStringView& wsID,
1593                                  WideStringView& wsSOM) {
1594   if (wsUseVal.IsEmpty())
1595     return;
1596 
1597   auto uSharpPos = wsUseVal.Find('#');
1598   if (!uSharpPos.has_value()) {
1599     wsURI = wsUseVal.AsStringView();
1600     return;
1601   }
1602   wsURI = wsUseVal.AsStringView().First(uSharpPos.value());
1603   if (wsUseVal.AsStringView().Substr(uSharpPos.value(), 5) == L"#som(" &&
1604       wsUseVal.Back() == ')') {
1605     wsSOM = wsUseVal.AsStringView().Substr(
1606         uSharpPos.value() + 5,
1607         wsUseVal.GetLength() - 1 - uSharpPos.value() - 5);
1608     return;
1609   }
1610   wsID = wsUseVal.AsStringView().Substr(uSharpPos.value() + 1);
1611 }
1612 
1613 // static
ParseUse(const WideString & wsUseVal,WideStringView & wsID,WideStringView & wsSOM)1614 void CXFA_Document::ParseUse(const WideString& wsUseVal,
1615                              WideStringView& wsID,
1616                              WideStringView& wsSOM) {
1617   if (wsUseVal.IsEmpty())
1618     return;
1619 
1620   if (wsUseVal[0] == '#') {
1621     wsID = wsUseVal.AsStringView().Substr(1);
1622     return;
1623   }
1624   wsSOM = wsUseVal.AsStringView();
1625 }
1626 
DataMerge_CopyContainer(CXFA_Node * pTemplateNode,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bOneInstance,bool bDataMerge,bool bUpLevel)1627 CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
1628                                                   CXFA_Node* pFormNode,
1629                                                   CXFA_Node* pDataScope,
1630                                                   bool bOneInstance,
1631                                                   bool bDataMerge,
1632                                                   bool bUpLevel) {
1633   DCHECK(pTemplateNode->IsContainerNode());
1634   switch (pTemplateNode->GetElementType()) {
1635     case XFA_Element::Area:
1636     case XFA_Element::PageArea:
1637     case XFA_Element::Subform:
1638     case XFA_Element::SubformSet:
1639       return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
1640                                       pDataScope, bOneInstance, bDataMerge);
1641     case XFA_Element::ContentArea:
1642     case XFA_Element::Draw:
1643     case XFA_Element::ExclGroup:
1644     case XFA_Element::Field:
1645       return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
1646                                  bDataMerge, bUpLevel);
1647     case XFA_Element::PageSet:
1648     case XFA_Element::Variables:
1649       return nullptr;
1650     default:
1651       NOTREACHED_NORETURN();
1652   }
1653 }
1654 
DataMerge_UpdateBindingRelations(CXFA_Node * pFormUpdateRoot)1655 void CXFA_Document::DataMerge_UpdateBindingRelations(
1656     CXFA_Node* pFormUpdateRoot) {
1657   CXFA_Node* pDataScope =
1658       XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
1659   if (!pDataScope)
1660     return;
1661 
1662   UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
1663   UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
1664 }
1665 
GetNotBindNode(pdfium::span<cppgc::Member<CXFA_Object>> arrayObjects) const1666 CXFA_Node* CXFA_Document::GetNotBindNode(
1667     pdfium::span<cppgc::Member<CXFA_Object>> arrayObjects) const {
1668   for (auto& pObject : arrayObjects) {
1669     CXFA_Node* pNode = pObject->AsNode();
1670     if (pNode && !pNode->HasBindItem())
1671       return pNode;
1672   }
1673   return nullptr;
1674 }
1675 
DoDataMerge()1676 void CXFA_Document::DoDataMerge() {
1677   CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
1678   if (!pDatasetsRoot) {
1679     // Ownership will be passed in the AppendChild below to the XML tree.
1680     auto* pDatasetsXMLNode =
1681         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1682             L"xfa:datasets");
1683     pDatasetsXMLNode->SetAttribute(L"xmlns:xfa",
1684                                    L"http://www.xfa.org/schema/xfa-data/1.0/");
1685     pDatasetsRoot =
1686         CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
1687     pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets");
1688 
1689     m_pRootNode->GetXMLMappingNode()->AppendLastChild(pDatasetsXMLNode);
1690     m_pRootNode->InsertChildAndNotify(pDatasetsRoot, nullptr);
1691     pDatasetsRoot->SetXMLMappingNode(pDatasetsXMLNode);
1692   }
1693 
1694   CXFA_Node* pDataRoot = nullptr;
1695   CXFA_Node* pDDRoot = nullptr;
1696   WideString wsDatasetsURI =
1697       pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
1698   for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
1699        pChildNode = pChildNode->GetNextSibling()) {
1700     if (pChildNode->GetElementType() != XFA_Element::DataGroup)
1701       continue;
1702 
1703     if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
1704       absl::optional<WideString> namespaceURI =
1705           pChildNode->JSObject()->TryNamespace();
1706       if (!namespaceURI.has_value())
1707         continue;
1708       if (namespaceURI.value().EqualsASCII(
1709               "http://ns.adobe.com/data-description/")) {
1710         pDDRoot = pChildNode;
1711       }
1712     } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
1713       absl::optional<WideString> namespaceURI =
1714           pChildNode->JSObject()->TryNamespace();
1715       if (!namespaceURI.has_value())
1716         continue;
1717       if (namespaceURI == wsDatasetsURI)
1718         pDataRoot = pChildNode;
1719     }
1720     if (pDataRoot && pDDRoot)
1721       break;
1722   }
1723 
1724   if (!pDataRoot) {
1725     pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
1726     pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data");
1727 
1728     auto* elem =
1729         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1730             L"xfa:data");
1731     pDataRoot->SetXMLMappingNode(elem);
1732     pDatasetsRoot->InsertChildAndNotify(pDataRoot, nullptr);
1733   }
1734 
1735   CXFA_DataGroup* pDataTopLevel =
1736       pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
1737   uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
1738   CXFA_Template* pTemplateRoot =
1739       m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
1740   if (!pTemplateRoot)
1741     return;
1742 
1743   CXFA_Node* pTemplateChosen =
1744       dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
1745                       : nullptr;
1746   if (!pTemplateChosen ||
1747       pTemplateChosen->GetElementType() != XFA_Element::Subform) {
1748     pTemplateChosen =
1749         pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1750   }
1751   if (!pTemplateChosen)
1752     return;
1753 
1754   CXFA_Form* pFormRoot =
1755       m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
1756   bool bEmptyForm = false;
1757   if (!pFormRoot) {
1758     bEmptyForm = true;
1759     pFormRoot = static_cast<CXFA_Form*>(
1760         CreateNode(XFA_PacketType::Form, XFA_Element::Form));
1761     DCHECK(pFormRoot);
1762     pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form");
1763     m_pRootNode->InsertChildAndNotify(pFormRoot, nullptr);
1764   } else {
1765     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1766         sIterator(pFormRoot);
1767     for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
1768          pNode = sIterator.MoveToNext()) {
1769       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
1770     }
1771   }
1772 
1773   CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1774       this, pFormRoot, pTemplateChosen, false, nullptr);
1775   DCHECK(pSubformSetNode);
1776   if (!pDataTopLevel) {
1777     WideString wsFormName =
1778         pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
1779     WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
1780 
1781     pDataTopLevel = static_cast<CXFA_DataGroup*>(
1782         CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
1783     pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name,
1784                                         wsDataTopLevelName);
1785 
1786     auto* elem =
1787         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1788             wsDataTopLevelName);
1789     pDataTopLevel->SetXMLMappingNode(elem);
1790 
1791     CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
1792     pDataRoot->InsertChildAndNotify(pDataTopLevel, pBeforeNode);
1793   }
1794 
1795   DCHECK(pDataTopLevel);
1796   CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
1797   for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
1798        pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
1799     if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
1800       XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
1801                                           true, nullptr);
1802     } else if (pTemplateChild->IsContainerNode()) {
1803       DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
1804                               false, true, true);
1805     }
1806   }
1807   if (pDDRoot)
1808     UpdateDataRelation(pDataRoot, pDDRoot);
1809 
1810   DataMerge_UpdateBindingRelations(pSubformSetNode);
1811   CXFA_PageSet* pPageSetNode =
1812       pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
1813   while (pPageSetNode) {
1814     m_pPendingPageSet.push_back(pPageSetNode);
1815     CXFA_PageSet* pNextPageSetNode =
1816         pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
1817             XFA_Element::PageSet);
1818     pSubformSetNode->RemoveChildAndNotify(pPageSetNode, true);
1819     pPageSetNode = pNextPageSetNode;
1820   }
1821 
1822   if (bEmptyForm)
1823     return;
1824 
1825   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
1826       pFormRoot);
1827   CXFA_Node* pNode = sIterator.MoveToNext();
1828   while (pNode) {
1829     if (pNode->IsUnusedNode()) {
1830       if (pNode->IsContainerNode() ||
1831           pNode->GetElementType() == XFA_Element::InstanceManager) {
1832         CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
1833         pNode->GetParent()->RemoveChildAndNotify(pNode, true);
1834         pNode = pNext;
1835       } else {
1836         pNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
1837         pNode->SetInitializedFlagAndNotify();
1838         pNode = sIterator.MoveToNext();
1839       }
1840     } else {
1841       pNode->SetInitializedFlagAndNotify();
1842       pNode = sIterator.MoveToNext();
1843     }
1844   }
1845 }
1846 
DoDataRemerge()1847 void CXFA_Document::DoDataRemerge() {
1848   CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
1849   if (pFormRoot) {
1850     while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
1851       pFormRoot->RemoveChildAndNotify(pNode, true);
1852 
1853     pFormRoot->SetBindingNode(nullptr);
1854   }
1855   m_rgGlobalBinding.clear();
1856   DoDataMerge();
1857   GetLayoutProcessor()->SetForceRelayout();
1858 }
1859 
GetGlobalBinding(uint32_t dwNameHash)1860 CXFA_Node* CXFA_Document::GetGlobalBinding(uint32_t dwNameHash) {
1861   auto it = m_rgGlobalBinding.find(dwNameHash);
1862   return it != m_rgGlobalBinding.end() ? it->second : nullptr;
1863 }
1864 
RegisterGlobalBinding(uint32_t dwNameHash,CXFA_Node * pDataNode)1865 void CXFA_Document::RegisterGlobalBinding(uint32_t dwNameHash,
1866                                           CXFA_Node* pDataNode) {
1867   m_rgGlobalBinding[dwNameHash] = pDataNode;
1868 }
1869 
GetPendingNodesCount() const1870 size_t CXFA_Document::GetPendingNodesCount() const {
1871   return m_pPendingPageSet.size();
1872 }
1873 
GetPendingNodeAtIndex(size_t index) const1874 CXFA_Node* CXFA_Document::GetPendingNodeAtIndex(size_t index) const {
1875   return m_pPendingPageSet[index];
1876 }
1877 
AppendPendingNode(CXFA_Node * node)1878 void CXFA_Document::AppendPendingNode(CXFA_Node* node) {
1879   m_pPendingPageSet.push_back(node);
1880 }
1881 
ClearPendingNodes()1882 void CXFA_Document::ClearPendingNodes() {
1883   m_pPendingPageSet.clear();
1884 }
1885 
SetPendingNodesUnusedAndUnbound()1886 void CXFA_Document::SetPendingNodesUnusedAndUnbound() {
1887   for (CXFA_Node* pPageNode : m_pPendingPageSet) {
1888     CXFA_NodeIterator sIterator(pPageNode);
1889     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1890          pNode = sIterator.MoveToNext()) {
1891       if (pNode->IsContainerNode()) {
1892         CXFA_Node* pBindNode = pNode->GetBindData();
1893         if (pBindNode) {
1894           pBindNode->RemoveBindItem(pNode);
1895           pNode->SetBindingNode(nullptr);
1896         }
1897       }
1898       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
1899     }
1900   }
1901 }
1902 
1903 CXFA_Document::LayoutProcessorIface::LayoutProcessorIface() = default;
1904 
1905 CXFA_Document::LayoutProcessorIface::~LayoutProcessorIface() = default;
1906 
Trace(cppgc::Visitor * visitor) const1907 void CXFA_Document::LayoutProcessorIface::Trace(cppgc::Visitor* visitor) const {
1908   visitor->Trace(m_pDocument);
1909 }
1910