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