xref: /aosp_15_r20/external/pdfium/fxjs/xfa/cjx_tree.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fxjs/xfa/cjx_tree.h"
8 
9 #include <vector>
10 
11 #include "fxjs/fxv8.h"
12 #include "fxjs/js_resources.h"
13 #include "fxjs/xfa/cfxjse_class.h"
14 #include "fxjs/xfa/cfxjse_engine.h"
15 #include "third_party/base/numerics/safe_conversions.h"
16 #include "v8/include/cppgc/allocation.h"
17 #include "v8/include/v8-object.h"
18 #include "v8/include/v8-primitive.h"
19 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
20 #include "xfa/fxfa/parser/cxfa_attachnodelist.h"
21 #include "xfa/fxfa/parser/cxfa_document.h"
22 #include "xfa/fxfa/parser/cxfa_node.h"
23 #include "xfa/fxfa/parser/cxfa_object.h"
24 
25 const CJX_MethodSpec CJX_Tree::MethodSpecs[] = {
26     {"resolveNode", resolveNode_static},
27     {"resolveNodes", resolveNodes_static}};
28 
CJX_Tree(CXFA_Object * obj)29 CJX_Tree::CJX_Tree(CXFA_Object* obj) : CJX_Object(obj) {
30   DefineMethods(MethodSpecs);
31 }
32 
33 CJX_Tree::~CJX_Tree() = default;
34 
DynamicTypeIs(TypeTag eType) const35 bool CJX_Tree::DynamicTypeIs(TypeTag eType) const {
36   return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
37 }
38 
resolveNode(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)39 CJS_Result CJX_Tree::resolveNode(
40     CFXJSE_Engine* runtime,
41     const std::vector<v8::Local<v8::Value>>& params) {
42   if (params.size() != 1)
43     return CJS_Result::Failure(JSMessage::kParamError);
44 
45   WideString wsExpression = runtime->ToWideString(params[0]);
46   CXFA_Object* pRefNode = GetXFAObject();
47   if (pRefNode->GetElementType() == XFA_Element::Xfa)
48     pRefNode = runtime->GetThisObject();
49 
50   absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
51       runtime->ResolveObjects(
52           ToNode(pRefNode), wsExpression.AsStringView(),
53           Mask<XFA_ResolveFlag>{
54               XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
55               XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
56               XFA_ResolveFlag::kSiblings});
57   if (!maybeResult.has_value())
58     return CJS_Result::Success(runtime->NewNull());
59 
60   if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
61     return CJS_Result::Success(runtime->GetOrCreateJSBindingFromMap(
62         maybeResult.value().objects.front().Get()));
63   }
64 
65   if (!maybeResult.value().script_attribute.callback ||
66       maybeResult.value().script_attribute.eValueType !=
67           XFA_ScriptType::Object) {
68     return CJS_Result::Success(runtime->NewNull());
69   }
70 
71   v8::Local<v8::Value> pValue;
72   CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
73   (*maybeResult.value().script_attribute.callback)(
74       runtime->GetIsolate(), jsObject, &pValue, false,
75       maybeResult.value().script_attribute.attribute);
76   return CJS_Result::Success(pValue);
77 }
78 
resolveNodes(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)79 CJS_Result CJX_Tree::resolveNodes(
80     CFXJSE_Engine* runtime,
81     const std::vector<v8::Local<v8::Value>>& params) {
82   if (params.size() != 1)
83     return CJS_Result::Failure(JSMessage::kParamError);
84 
85   CXFA_Object* refNode = GetXFAObject();
86   if (refNode->GetElementType() == XFA_Element::Xfa)
87     refNode = runtime->GetThisObject();
88 
89   const Mask<XFA_ResolveFlag> kFlags = {
90       XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
91       XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
92       XFA_ResolveFlag::kSiblings};
93   return CJS_Result::Success(ResolveNodeList(runtime->GetIsolate(),
94                                              runtime->ToWideString(params[0]),
95                                              kFlags, ToNode(refNode)));
96 }
97 
all(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)98 void CJX_Tree::all(v8::Isolate* pIsolate,
99                    v8::Local<v8::Value>* pValue,
100                    bool bSetting,
101                    XFA_Attribute eAttribute) {
102   if (bSetting) {
103     ThrowInvalidPropertyException(pIsolate);
104     return;
105   }
106   const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
107                                         XFA_ResolveFlag::kALL};
108   WideString wsExpression = GetAttributeByEnum(XFA_Attribute::Name) + L"[*]";
109   *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
110 }
111 
classAll(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)112 void CJX_Tree::classAll(v8::Isolate* pIsolate,
113                         v8::Local<v8::Value>* pValue,
114                         bool bSetting,
115                         XFA_Attribute eAttribute) {
116   if (bSetting) {
117     ThrowInvalidPropertyException(pIsolate);
118     return;
119   }
120   const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
121                                         XFA_ResolveFlag::kALL};
122   WideString wsExpression =
123       L"#" + WideString::FromASCII(GetXFAObject()->GetClassName()) + L"[*]";
124   *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
125 }
126 
nodes(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)127 void CJX_Tree::nodes(v8::Isolate* pIsolate,
128                      v8::Local<v8::Value>* pValue,
129                      bool bSetting,
130                      XFA_Attribute eAttribute) {
131   if (bSetting) {
132     WideString wsMessage = L"Unable to set ";
133     FXJSE_ThrowMessage(pIsolate, wsMessage.ToUTF8().AsStringView());
134     return;
135   }
136 
137   CXFA_Document* pDoc = GetDocument();
138   auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_AttachNodeList>(
139       pDoc->GetHeap()->GetAllocationHandle(), pDoc, GetXFANode());
140   pDoc->GetNodeOwner()->PersistList(pNodeList);
141 
142   CFXJSE_Engine* pEngine = pDoc->GetScriptContext();
143   *pValue = pNodeList->JSObject()->NewBoundV8Object(
144       pIsolate, pEngine->GetJseNormalClass()->GetTemplate(pIsolate));
145 }
146 
parent(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)147 void CJX_Tree::parent(v8::Isolate* pIsolate,
148                       v8::Local<v8::Value>* pValue,
149                       bool bSetting,
150                       XFA_Attribute eAttribute) {
151   if (bSetting) {
152     ThrowInvalidPropertyException(pIsolate);
153     return;
154   }
155 
156   CXFA_Node* pParent = GetXFANode()->GetParent();
157   *pValue = pParent ? GetDocument()
158                           ->GetScriptContext()
159                           ->GetOrCreateJSBindingFromMap(pParent)
160                           .As<v8::Value>()
161                     : fxv8::NewNullHelper(pIsolate).As<v8::Value>();
162 }
163 
index(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)164 void CJX_Tree::index(v8::Isolate* pIsolate,
165                      v8::Local<v8::Value>* pValue,
166                      bool bSetting,
167                      XFA_Attribute eAttribute) {
168   if (bSetting) {
169     ThrowInvalidPropertyException(pIsolate);
170     return;
171   }
172 
173   CXFA_Node* pNode = GetXFANode();
174   size_t iIndex = pNode ? pNode->GetIndexByName() : 0;
175   *pValue = fxv8::NewNumberHelper(pIsolate,
176                                   pdfium::base::checked_cast<int32_t>(iIndex));
177 }
178 
classIndex(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)179 void CJX_Tree::classIndex(v8::Isolate* pIsolate,
180                           v8::Local<v8::Value>* pValue,
181                           bool bSetting,
182                           XFA_Attribute eAttribute) {
183   if (bSetting) {
184     ThrowInvalidPropertyException(pIsolate);
185     return;
186   }
187 
188   CXFA_Node* pNode = GetXFANode();
189   size_t iIndex = pNode ? pNode->GetIndexByClassName() : 0;
190   *pValue = fxv8::NewNumberHelper(pIsolate,
191                                   pdfium::base::checked_cast<int32_t>(iIndex));
192 }
193 
somExpression(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)194 void CJX_Tree::somExpression(v8::Isolate* pIsolate,
195                              v8::Local<v8::Value>* pValue,
196                              bool bSetting,
197                              XFA_Attribute eAttribute) {
198   if (bSetting) {
199     ThrowInvalidPropertyException(pIsolate);
200     return;
201   }
202 
203   ByteString bsSOMExpression = GetXFAObject()->GetSOMExpression().ToUTF8();
204   *pValue = fxv8::NewStringHelper(pIsolate, bsSOMExpression.AsStringView());
205 }
206 
ResolveNodeList(v8::Isolate * pIsolate,WideString wsExpression,Mask<XFA_ResolveFlag> dwFlag,CXFA_Node * refNode)207 v8::Local<v8::Value> CJX_Tree::ResolveNodeList(v8::Isolate* pIsolate,
208                                                WideString wsExpression,
209                                                Mask<XFA_ResolveFlag> dwFlag,
210                                                CXFA_Node* refNode) {
211   if (!refNode)
212     refNode = GetXFANode();
213 
214   CXFA_Document* pDoc = GetDocument();
215   auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_ArrayNodeList>(
216       pDoc->GetHeap()->GetAllocationHandle(), pDoc);
217   pDoc->GetNodeOwner()->PersistList(pNodeList);
218 
219   CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
220   absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
221       pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
222                                      dwFlag);
223 
224   if (maybeResult.has_value()) {
225     if (maybeResult.value().type ==
226         CFXJSE_Engine::ResolveResult::Type::kNodes) {
227       for (auto& pObject : maybeResult.value().objects) {
228         if (pObject->IsNode())
229           pNodeList->Append(pObject->AsNode());
230       }
231     } else {
232       if (maybeResult.value().script_attribute.callback &&
233           maybeResult.value().script_attribute.eValueType ==
234               XFA_ScriptType::Object) {
235         for (auto& pObject : maybeResult.value().objects) {
236           v8::Local<v8::Value> innerValue;
237           CJX_Object* jsObject = pObject->JSObject();
238           (*maybeResult.value().script_attribute.callback)(
239               pIsolate, jsObject, &innerValue, false,
240               maybeResult.value().script_attribute.attribute);
241           CXFA_Object* obj =
242               CFXJSE_Engine::ToObject(pScriptContext->GetIsolate(), innerValue);
243           if (obj->IsNode())
244             pNodeList->Append(obj->AsNode());
245         }
246       }
247     }
248   }
249   return pNodeList->JSObject()->NewBoundV8Object(
250       pIsolate, pScriptContext->GetJseNormalClass()->GetTemplate(pIsolate));
251 }
252