Home | History | Annotate | Download | only in fxjs
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fxjs/cfxjse_engine.h"
      8 
      9 #include <utility>
     10 
     11 #include "core/fxcrt/autorestorer.h"
     12 #include "core/fxcrt/cfx_widetextbuf.h"
     13 #include "core/fxcrt/fx_extension.h"
     14 #include "fxjs/cfxjse_class.h"
     15 #include "fxjs/cfxjse_resolveprocessor.h"
     16 #include "fxjs/cfxjse_value.h"
     17 #include "third_party/base/ptr_util.h"
     18 #include "third_party/base/stl_util.h"
     19 #include "xfa/fxfa/cxfa_eventparam.h"
     20 #include "xfa/fxfa/cxfa_ffnotify.h"
     21 #include "xfa/fxfa/parser/cxfa_document.h"
     22 #include "xfa/fxfa/parser/cxfa_localemgr.h"
     23 #include "xfa/fxfa/parser/cxfa_node.h"
     24 #include "xfa/fxfa/parser/cxfa_nodehelper.h"
     25 #include "xfa/fxfa/parser/cxfa_object.h"
     26 #include "xfa/fxfa/parser/cxfa_thisproxy.h"
     27 #include "xfa/fxfa/parser/cxfa_treelist.h"
     28 #include "xfa/fxfa/parser/xfa_basic_data.h"
     29 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
     30 #include "xfa/fxfa/parser/xfa_utils.h"
     31 
     32 namespace {
     33 
     34 const FXJSE_CLASS_DESCRIPTOR GlobalClassDescriptor = {
     35     "Root",   // name
     36     nullptr,  // methods
     37     0,        // method count
     38     CFXJSE_Engine::GlobalPropTypeGetter,
     39     CFXJSE_Engine::GlobalPropertyGetter,
     40     CFXJSE_Engine::GlobalPropertySetter,
     41     CFXJSE_Engine::NormalMethodCall,
     42 };
     43 
     44 const FXJSE_CLASS_DESCRIPTOR NormalClassDescriptor = {
     45     "XFAObject",  // name
     46     nullptr,      // methods
     47     0,            // method count
     48     CFXJSE_Engine::NormalPropTypeGetter,
     49     CFXJSE_Engine::NormalPropertyGetter,
     50     CFXJSE_Engine::NormalPropertySetter,
     51     CFXJSE_Engine::NormalMethodCall,
     52 };
     53 
     54 const FXJSE_CLASS_DESCRIPTOR VariablesClassDescriptor = {
     55     "XFAScriptObject",  // name
     56     nullptr,            // methods
     57     0,                  // method count
     58     CFXJSE_Engine::NormalPropTypeGetter,
     59     CFXJSE_Engine::GlobalPropertyGetter,
     60     CFXJSE_Engine::GlobalPropertySetter,
     61     CFXJSE_Engine::NormalMethodCall,
     62 };
     63 
     64 const char kFormCalcRuntime[] = "pfm_rt";
     65 
     66 CXFA_ThisProxy* ToThisProxy(CFXJSE_Value* pValue, CFXJSE_Class* pClass) {
     67   return static_cast<CXFA_ThisProxy*>(pValue->ToHostObject(pClass));
     68 }
     69 
     70 }  // namespace
     71 
     72 // static
     73 CXFA_Object* CFXJSE_Engine::ToObject(
     74     const v8::FunctionCallbackInfo<v8::Value>& info) {
     75   if (!info.Holder()->IsObject())
     76     return nullptr;
     77 
     78   CFXJSE_HostObject* hostObj =
     79       FXJSE_RetrieveObjectBinding(info.Holder().As<v8::Object>(), nullptr);
     80   if (!hostObj || hostObj->type() != CFXJSE_HostObject::kXFA)
     81     return nullptr;
     82   return static_cast<CXFA_Object*>(hostObj);
     83 }
     84 
     85 // static.
     86 CXFA_Object* CFXJSE_Engine::ToObject(CFXJSE_Value* pValue,
     87                                      CFXJSE_Class* pClass) {
     88   CFXJSE_HostObject* pHostObj = pValue->ToHostObject(pClass);
     89   if (!pHostObj || pHostObj->type() != CFXJSE_HostObject::kXFA)
     90     return nullptr;
     91   return static_cast<CXFA_Object*>(pHostObj);
     92 }
     93 
     94 CFXJSE_Engine::CFXJSE_Engine(CXFA_Document* pDocument, v8::Isolate* pIsolate)
     95     : CJS_V8(pIsolate),
     96       m_pDocument(pDocument),
     97       m_JsContext(CFXJSE_Context::Create(pIsolate,
     98                                          &GlobalClassDescriptor,
     99                                          pDocument->GetRoot())),
    100       m_pJsClass(nullptr),
    101       m_eScriptType(CXFA_Script::Type::Unknown),
    102       m_pScriptNodeArray(nullptr),
    103       m_ResolveProcessor(pdfium::MakeUnique<CFXJSE_ResolveProcessor>()),
    104       m_pThisObject(nullptr),
    105       m_eRunAtType(XFA_AttributeEnum::Client) {
    106   RemoveBuiltInObjs(m_JsContext.get());
    107   m_JsContext->EnableCompatibleMode();
    108 
    109   // Don't know if this can happen before we remove the builtin objs and set
    110   // compatibility mode.
    111   m_pJsClass =
    112       CFXJSE_Class::Create(m_JsContext.get(), &NormalClassDescriptor, false);
    113 }
    114 
    115 CFXJSE_Engine::~CFXJSE_Engine() {
    116   for (const auto& pair : m_mapVariableToContext)
    117     delete ToThisProxy(pair.second->GetGlobalObject().get(), nullptr);
    118 }
    119 
    120 bool CFXJSE_Engine::RunScript(CXFA_Script::Type eScriptType,
    121                               const WideStringView& wsScript,
    122                               CFXJSE_Value* hRetValue,
    123                               CXFA_Object* pThisObject) {
    124   ByteString btScript;
    125   AutoRestorer<CXFA_Script::Type> typeRestorer(&m_eScriptType);
    126   m_eScriptType = eScriptType;
    127   if (eScriptType == CXFA_Script::Type::Formcalc) {
    128     if (!m_FM2JSContext) {
    129       m_FM2JSContext = pdfium::MakeUnique<CFXJSE_FormCalcContext>(
    130           GetIsolate(), m_JsContext.get(), m_pDocument.Get());
    131     }
    132     CFX_WideTextBuf wsJavaScript;
    133     if (!CFXJSE_FormCalcContext::Translate(wsScript, &wsJavaScript)) {
    134       hRetValue->SetUndefined();
    135       return false;
    136     }
    137     btScript = FX_UTF8Encode(wsJavaScript.AsStringView());
    138   } else {
    139     btScript = FX_UTF8Encode(wsScript);
    140   }
    141   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
    142   m_pThisObject = pThisObject;
    143   CFXJSE_Value* pValue = pThisObject ? GetJSValueFromMap(pThisObject) : nullptr;
    144   return m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
    145 }
    146 
    147 bool CFXJSE_Engine::QueryNodeByFlag(CXFA_Node* refNode,
    148                                     const WideStringView& propname,
    149                                     CFXJSE_Value* pValue,
    150                                     uint32_t dwFlag,
    151                                     bool bSetting) {
    152   if (!refNode)
    153     return false;
    154 
    155   XFA_RESOLVENODE_RS resolveRs;
    156   if (!ResolveObjects(refNode, propname, &resolveRs, dwFlag, nullptr))
    157     return false;
    158   if (resolveRs.dwFlags == XFA_ResolveNode_RSType_Nodes) {
    159     pValue->Assign(GetJSValueFromMap(resolveRs.objects.front()));
    160     return true;
    161   }
    162   if (resolveRs.dwFlags == XFA_ResolveNode_RSType_Attribute) {
    163     const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo = resolveRs.pScriptAttribute;
    164     if (lpAttributeInfo) {
    165       CJX_Object* jsObject = resolveRs.objects.front()->JSObject();
    166       (jsObject->*(lpAttributeInfo->callback))(pValue, bSetting,
    167                                                lpAttributeInfo->attribute);
    168     }
    169   }
    170   return true;
    171 }
    172 
    173 void CFXJSE_Engine::GlobalPropertySetter(CFXJSE_Value* pObject,
    174                                          const ByteStringView& szPropName,
    175                                          CFXJSE_Value* pValue) {
    176   CXFA_Object* lpOrginalNode = ToObject(pObject, nullptr);
    177   CXFA_Document* pDoc = lpOrginalNode->GetDocument();
    178   CFXJSE_Engine* lpScriptContext = pDoc->GetScriptContext();
    179   CXFA_Node* pRefNode = ToNode(lpScriptContext->GetThisObject());
    180   if (lpOrginalNode->IsVariablesThis())
    181     pRefNode = ToNode(lpScriptContext->GetVariablesThis(lpOrginalNode));
    182 
    183   WideString wsPropName = WideString::FromUTF8(szPropName);
    184   if (lpScriptContext->QueryNodeByFlag(
    185           pRefNode, wsPropName.AsStringView(), pValue,
    186           XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings |
    187               XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
    188               XFA_RESOLVENODE_Attributes,
    189           true)) {
    190     return;
    191   }
    192   if (lpOrginalNode->IsVariablesThis()) {
    193     if (pValue && pValue->IsUndefined()) {
    194       pObject->SetObjectOwnProperty(szPropName, pValue);
    195       return;
    196     }
    197   }
    198   CXFA_FFNotify* pNotify = pDoc->GetNotify();
    199   if (!pNotify)
    200     return;
    201 
    202   pNotify->GetDocEnvironment()->SetGlobalProperty(pNotify->GetHDOC(),
    203                                                   szPropName, pValue);
    204 }
    205 
    206 void CFXJSE_Engine::GlobalPropertyGetter(CFXJSE_Value* pObject,
    207                                          const ByteStringView& szPropName,
    208                                          CFXJSE_Value* pValue) {
    209   CXFA_Object* pOriginalObject = ToObject(pObject, nullptr);
    210   CXFA_Document* pDoc = pOriginalObject->GetDocument();
    211   CFXJSE_Engine* lpScriptContext = pDoc->GetScriptContext();
    212   WideString wsPropName = WideString::FromUTF8(szPropName);
    213   if (lpScriptContext->GetType() == CXFA_Script::Type::Formcalc) {
    214     if (szPropName == kFormCalcRuntime) {
    215       lpScriptContext->m_FM2JSContext->GlobalPropertyGetter(pValue);
    216       return;
    217     }
    218     XFA_HashCode uHashCode = static_cast<XFA_HashCode>(
    219         FX_HashCode_GetW(wsPropName.AsStringView(), false));
    220     if (uHashCode != XFA_HASHCODE_Layout) {
    221       CXFA_Object* pObj =
    222           lpScriptContext->GetDocument()->GetXFAObject(uHashCode);
    223       if (pObj) {
    224         pValue->Assign(lpScriptContext->GetJSValueFromMap(pObj));
    225         return;
    226       }
    227     }
    228   }
    229 
    230   CXFA_Node* pRefNode = ToNode(lpScriptContext->GetThisObject());
    231   if (pOriginalObject->IsVariablesThis())
    232     pRefNode = ToNode(lpScriptContext->GetVariablesThis(pOriginalObject));
    233 
    234   if (lpScriptContext->QueryNodeByFlag(
    235           pRefNode, wsPropName.AsStringView(), pValue,
    236           XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
    237               XFA_RESOLVENODE_Attributes,
    238           false)) {
    239     return;
    240   }
    241 
    242   if (lpScriptContext->QueryNodeByFlag(
    243           pRefNode, wsPropName.AsStringView(), pValue,
    244           XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings, false)) {
    245     return;
    246   }
    247 
    248   CXFA_Object* pScriptObject =
    249       lpScriptContext->GetVariablesThis(pOriginalObject, true);
    250   if (pScriptObject && lpScriptContext->QueryVariableValue(
    251                            pScriptObject->AsNode(), szPropName, pValue, true)) {
    252     return;
    253   }
    254 
    255   CXFA_FFNotify* pNotify = pDoc->GetNotify();
    256   if (!pNotify)
    257     return;
    258 
    259   pNotify->GetDocEnvironment()->GetGlobalProperty(pNotify->GetHDOC(),
    260                                                   szPropName, pValue);
    261 }
    262 
    263 int32_t CFXJSE_Engine::GlobalPropTypeGetter(CFXJSE_Value* pOriginalValue,
    264                                             const ByteStringView& szPropName,
    265                                             bool bQueryIn) {
    266   CXFA_Object* pObject = ToObject(pOriginalValue, nullptr);
    267   if (!pObject)
    268     return FXJSE_ClassPropType_None;
    269 
    270   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
    271   pObject = lpScriptContext->GetVariablesThis(pObject);
    272   WideString wsPropName = WideString::FromUTF8(szPropName);
    273   if (pObject->JSObject()->HasMethod(wsPropName))
    274     return FXJSE_ClassPropType_Method;
    275 
    276   return FXJSE_ClassPropType_Property;
    277 }
    278 
    279 void CFXJSE_Engine::NormalPropertyGetter(CFXJSE_Value* pOriginalValue,
    280                                          const ByteStringView& szPropName,
    281                                          CFXJSE_Value* pReturnValue) {
    282   CXFA_Object* pOriginalObject = ToObject(pOriginalValue, nullptr);
    283   if (!pOriginalObject) {
    284     pReturnValue->SetUndefined();
    285     return;
    286   }
    287 
    288   WideString wsPropName = WideString::FromUTF8(szPropName);
    289   CFXJSE_Engine* lpScriptContext =
    290       pOriginalObject->GetDocument()->GetScriptContext();
    291   CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOriginalObject);
    292   if (wsPropName == L"xfa") {
    293     CFXJSE_Value* pValue = lpScriptContext->GetJSValueFromMap(
    294         lpScriptContext->GetDocument()->GetRoot());
    295     pReturnValue->Assign(pValue);
    296     return;
    297   }
    298 
    299   bool bRet = lpScriptContext->QueryNodeByFlag(
    300       ToNode(pObject), wsPropName.AsStringView(), pReturnValue,
    301       XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
    302           XFA_RESOLVENODE_Attributes,
    303       false);
    304   if (bRet)
    305     return;
    306 
    307   if (pObject == lpScriptContext->GetThisObject() ||
    308       (lpScriptContext->GetType() == CXFA_Script::Type::Javascript &&
    309        !lpScriptContext->IsStrictScopeInJavaScript())) {
    310     bRet = lpScriptContext->QueryNodeByFlag(
    311         ToNode(pObject), wsPropName.AsStringView(), pReturnValue,
    312         XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings, false);
    313   }
    314   if (bRet)
    315     return;
    316 
    317   CXFA_Object* pScriptObject =
    318       lpScriptContext->GetVariablesThis(pOriginalObject, true);
    319   if (pScriptObject) {
    320     bRet = lpScriptContext->QueryVariableValue(ToNode(pScriptObject),
    321                                                szPropName, pReturnValue, true);
    322   }
    323   if (!bRet)
    324     pReturnValue->SetUndefined();
    325 }
    326 
    327 void CFXJSE_Engine::NormalPropertySetter(CFXJSE_Value* pOriginalValue,
    328                                          const ByteStringView& szPropName,
    329                                          CFXJSE_Value* pReturnValue) {
    330   CXFA_Object* pOriginalObject = ToObject(pOriginalValue, nullptr);
    331   if (!pOriginalObject)
    332     return;
    333 
    334   CFXJSE_Engine* lpScriptContext =
    335       pOriginalObject->GetDocument()->GetScriptContext();
    336   CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOriginalObject);
    337   WideString wsPropName = WideString::FromUTF8(szPropName);
    338   const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo = XFA_GetScriptAttributeByName(
    339       pObject->GetElementType(), wsPropName.AsStringView());
    340   if (lpAttributeInfo) {
    341     CJX_Object* jsObject = pObject->JSObject();
    342     (jsObject->*(lpAttributeInfo->callback))(pReturnValue, true,
    343                                              lpAttributeInfo->attribute);
    344     return;
    345   }
    346 
    347   if (pObject->IsNode()) {
    348     if (wsPropName[0] == '#')
    349       wsPropName = wsPropName.Right(wsPropName.GetLength() - 1);
    350 
    351     CXFA_Node* pNode = ToNode(pObject);
    352     CXFA_Node* pPropOrChild = nullptr;
    353     XFA_Element eType = CXFA_Node::NameToElement(wsPropName);
    354     if (eType != XFA_Element::Unknown) {
    355       pPropOrChild =
    356           pNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eType);
    357     } else {
    358       pPropOrChild = pNode->GetFirstChildByName(wsPropName.AsStringView());
    359     }
    360 
    361     if (pPropOrChild) {
    362       const XFA_SCRIPTATTRIBUTEINFO* lpAttrInfo = XFA_GetScriptAttributeByName(
    363           pPropOrChild->GetElementType(), L"{default}");
    364       if (lpAttrInfo) {
    365         pPropOrChild->JSObject()->Script_Som_DefaultValue(
    366             pReturnValue, true, XFA_Attribute::Unknown);
    367         return;
    368       }
    369     }
    370   }
    371 
    372   CXFA_Object* pScriptObject =
    373       lpScriptContext->GetVariablesThis(pOriginalObject, true);
    374   if (pScriptObject) {
    375     lpScriptContext->QueryVariableValue(ToNode(pScriptObject), szPropName,
    376                                         pReturnValue, false);
    377   }
    378 }
    379 
    380 int32_t CFXJSE_Engine::NormalPropTypeGetter(CFXJSE_Value* pOriginalValue,
    381                                             const ByteStringView& szPropName,
    382                                             bool bQueryIn) {
    383   CXFA_Object* pObject = ToObject(pOriginalValue, nullptr);
    384   if (!pObject)
    385     return FXJSE_ClassPropType_None;
    386 
    387   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
    388   pObject = lpScriptContext->GetVariablesThis(pObject);
    389   XFA_Element eType = pObject->GetElementType();
    390   WideString wsPropName = WideString::FromUTF8(szPropName);
    391   if (pObject->JSObject()->HasMethod(wsPropName))
    392     return FXJSE_ClassPropType_Method;
    393 
    394   if (bQueryIn &&
    395       !XFA_GetScriptAttributeByName(eType, wsPropName.AsStringView())) {
    396     return FXJSE_ClassPropType_None;
    397   }
    398   return FXJSE_ClassPropType_Property;
    399 }
    400 
    401 CJS_Return CFXJSE_Engine::NormalMethodCall(
    402     const v8::FunctionCallbackInfo<v8::Value>& info,
    403     const WideString& functionName) {
    404   CXFA_Object* pObject = ToObject(info);
    405   if (!pObject)
    406     return CJS_Return(false);
    407 
    408   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
    409   pObject = lpScriptContext->GetVariablesThis(pObject);
    410 
    411   std::vector<v8::Local<v8::Value>> parameters;
    412   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++)
    413     parameters.push_back(info[i]);
    414 
    415   return pObject->JSObject()->RunMethod(functionName, parameters);
    416 }
    417 
    418 bool CFXJSE_Engine::IsStrictScopeInJavaScript() {
    419   return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping);
    420 }
    421 
    422 CXFA_Script::Type CFXJSE_Engine::GetType() {
    423   return m_eScriptType;
    424 }
    425 
    426 CFXJSE_Context* CFXJSE_Engine::CreateVariablesContext(CXFA_Node* pScriptNode,
    427                                                       CXFA_Node* pSubform) {
    428   if (!pScriptNode || !pSubform)
    429     return nullptr;
    430 
    431   auto pNewContext =
    432       CFXJSE_Context::Create(GetIsolate(), &VariablesClassDescriptor,
    433                              new CXFA_ThisProxy(pSubform, pScriptNode));
    434   RemoveBuiltInObjs(pNewContext.get());
    435   pNewContext->EnableCompatibleMode();
    436   CFXJSE_Context* pResult = pNewContext.get();
    437   m_mapVariableToContext[pScriptNode] = std::move(pNewContext);
    438   return pResult;
    439 }
    440 
    441 CXFA_Object* CFXJSE_Engine::GetVariablesThis(CXFA_Object* pObject,
    442                                              bool bScriptNode) {
    443   if (!pObject->IsVariablesThis())
    444     return pObject;
    445 
    446   CXFA_ThisProxy* pProxy = static_cast<CXFA_ThisProxy*>(pObject);
    447   return bScriptNode ? pProxy->GetScriptNode() : pProxy->GetThisNode();
    448 }
    449 
    450 bool CFXJSE_Engine::RunVariablesScript(CXFA_Node* pScriptNode) {
    451   if (!pScriptNode)
    452     return false;
    453 
    454   if (pScriptNode->GetElementType() != XFA_Element::Script)
    455     return true;
    456 
    457   CXFA_Node* pParent = pScriptNode->GetParent();
    458   if (!pParent || pParent->GetElementType() != XFA_Element::Variables)
    459     return false;
    460 
    461   auto it = m_mapVariableToContext.find(pScriptNode);
    462   if (it != m_mapVariableToContext.end() && it->second)
    463     return true;
    464 
    465   CXFA_Node* pTextNode = pScriptNode->GetFirstChild();
    466   if (!pTextNode)
    467     return false;
    468 
    469   Optional<WideString> wsScript =
    470       pTextNode->JSObject()->TryCData(XFA_Attribute::Value, true);
    471   if (!wsScript)
    472     return false;
    473 
    474   ByteString btScript = wsScript->UTF8Encode();
    475   auto hRetValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
    476   CXFA_Node* pThisObject = pParent->GetParent();
    477   CFXJSE_Context* pVariablesContext =
    478       CreateVariablesContext(pScriptNode, pThisObject);
    479   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
    480   m_pThisObject = pThisObject;
    481   return pVariablesContext->ExecuteScript(btScript.c_str(), hRetValue.get());
    482 }
    483 
    484 bool CFXJSE_Engine::QueryVariableValue(CXFA_Node* pScriptNode,
    485                                        const ByteStringView& szPropName,
    486                                        CFXJSE_Value* pValue,
    487                                        bool bGetter) {
    488   if (!pScriptNode || pScriptNode->GetElementType() != XFA_Element::Script)
    489     return false;
    490 
    491   CXFA_Node* variablesNode = pScriptNode->GetParent();
    492   if (!variablesNode ||
    493       variablesNode->GetElementType() != XFA_Element::Variables)
    494     return false;
    495 
    496   auto it = m_mapVariableToContext.find(pScriptNode);
    497   if (it == m_mapVariableToContext.end() || !it->second)
    498     return false;
    499 
    500   CFXJSE_Context* pVariableContext = it->second.get();
    501   std::unique_ptr<CFXJSE_Value> pObject = pVariableContext->GetGlobalObject();
    502   auto hVariableValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
    503   if (!bGetter) {
    504     pObject->SetObjectOwnProperty(szPropName, pValue);
    505     return true;
    506   }
    507   if (pObject->HasObjectOwnProperty(szPropName, false)) {
    508     pObject->GetObjectProperty(szPropName, hVariableValue.get());
    509     if (hVariableValue->IsFunction())
    510       pValue->SetFunctionBind(hVariableValue.get(), pObject.get());
    511     else if (bGetter)
    512       pValue->Assign(hVariableValue.get());
    513     else
    514       hVariableValue.get()->Assign(pValue);
    515     return true;
    516   }
    517   return false;
    518 }
    519 
    520 void CFXJSE_Engine::RemoveBuiltInObjs(CFXJSE_Context* pContext) const {
    521   static const ByteStringView OBJ_NAME[2] = {"Number", "Date"};
    522   std::unique_ptr<CFXJSE_Value> pObject = pContext->GetGlobalObject();
    523   auto hProp = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
    524   for (int i = 0; i < 2; ++i) {
    525     if (pObject->GetObjectProperty(OBJ_NAME[i], hProp.get()))
    526       pObject->DeleteObjectProperty(OBJ_NAME[i]);
    527   }
    528 }
    529 
    530 CFXJSE_Class* CFXJSE_Engine::GetJseNormalClass() {
    531   return m_pJsClass;
    532 }
    533 
    534 bool CFXJSE_Engine::ResolveObjects(CXFA_Object* refObject,
    535                                    const WideStringView& wsExpression,
    536                                    XFA_RESOLVENODE_RS* resolveNodeRS,
    537                                    uint32_t dwStyles,
    538                                    CXFA_Node* bindNode) {
    539   if (wsExpression.IsEmpty())
    540     return false;
    541 
    542   if (m_eScriptType != CXFA_Script::Type::Formcalc ||
    543       (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {
    544     m_upObjectArray.clear();
    545   }
    546   if (refObject && refObject->IsNode() &&
    547       (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {
    548     m_upObjectArray.push_back(refObject->AsNode());
    549   }
    550 
    551   bool bNextCreate = false;
    552   if (dwStyles & XFA_RESOLVENODE_CreateNode)
    553     m_ResolveProcessor->GetNodeHelper()->SetCreateNodeType(bindNode);
    554 
    555   m_ResolveProcessor->GetNodeHelper()->m_pCreateParent = nullptr;
    556   m_ResolveProcessor->GetNodeHelper()->m_iCurAllStart = -1;
    557 
    558   CFXJSE_ResolveNodeData rndFind(this);
    559   int32_t nStart = 0;
    560   int32_t nLevel = 0;
    561 
    562   std::vector<CXFA_Object*> findObjects;
    563   findObjects.push_back(refObject ? refObject : m_pDocument->GetRoot());
    564   int32_t nNodes = 0;
    565   while (true) {
    566     nNodes = pdfium::CollectionSize<int32_t>(findObjects);
    567     int32_t i = 0;
    568     rndFind.m_dwStyles = dwStyles;
    569     m_ResolveProcessor->SetCurStart(nStart);
    570     nStart = m_ResolveProcessor->GetFilter(wsExpression, nStart, rndFind);
    571     if (nStart < 1) {
    572       if ((dwStyles & XFA_RESOLVENODE_CreateNode) && !bNextCreate) {
    573         CXFA_Node* pDataNode = nullptr;
    574         nStart = m_ResolveProcessor->GetNodeHelper()->m_iCurAllStart;
    575         if (nStart != -1) {
    576           pDataNode = m_pDocument->GetNotBindNode(findObjects);
    577           if (pDataNode) {
    578             findObjects.clear();
    579             findObjects.push_back(pDataNode);
    580             break;
    581           }
    582         } else {
    583           pDataNode = findObjects.front()->AsNode();
    584           findObjects.clear();
    585           findObjects.push_back(pDataNode);
    586           break;
    587         }
    588         dwStyles |= XFA_RESOLVENODE_Bind;
    589         findObjects.clear();
    590         findObjects.push_back(
    591             m_ResolveProcessor->GetNodeHelper()->m_pAllStartParent);
    592         continue;
    593       }
    594       break;
    595     }
    596     if (bNextCreate) {
    597       bool bCreate =
    598           m_ResolveProcessor->GetNodeHelper()->ResolveNodes_CreateNode(
    599               rndFind.m_wsName, rndFind.m_wsCondition,
    600               nStart ==
    601                   pdfium::base::checked_cast<int32_t>(wsExpression.GetLength()),
    602               this);
    603       if (bCreate)
    604         continue;
    605 
    606       break;
    607     }
    608 
    609     std::vector<CXFA_Object*> retObjects;
    610     while (i < nNodes) {
    611       bool bDataBind = false;
    612       if (((dwStyles & XFA_RESOLVENODE_Bind) ||
    613            (dwStyles & XFA_RESOLVENODE_CreateNode)) &&
    614           nNodes > 1) {
    615         CFXJSE_ResolveNodeData rndBind(nullptr);
    616         m_ResolveProcessor->GetFilter(wsExpression, nStart, rndBind);
    617         m_ResolveProcessor->SetIndexDataBind(rndBind.m_wsCondition, i, nNodes);
    618         bDataBind = true;
    619       }
    620       rndFind.m_CurObject = findObjects[i++];
    621       rndFind.m_nLevel = nLevel;
    622       rndFind.m_dwFlag = XFA_ResolveNode_RSType_Nodes;
    623       if (!m_ResolveProcessor->Resolve(rndFind))
    624         continue;
    625 
    626       if (rndFind.m_dwFlag == XFA_ResolveNode_RSType_Attribute &&
    627           rndFind.m_pScriptAttribute &&
    628           nStart <
    629               pdfium::base::checked_cast<int32_t>(wsExpression.GetLength())) {
    630         auto pValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
    631         CJX_Object* jsObject = rndFind.m_Objects.front()->JSObject();
    632         (jsObject->*(rndFind.m_pScriptAttribute->callback))(
    633             pValue.get(), false, rndFind.m_pScriptAttribute->attribute);
    634         rndFind.m_Objects.front() = ToObject(pValue.get(), nullptr);
    635       }
    636       if (!m_upObjectArray.empty())
    637         m_upObjectArray.pop_back();
    638       retObjects.insert(retObjects.end(), rndFind.m_Objects.begin(),
    639                         rndFind.m_Objects.end());
    640       rndFind.m_Objects.clear();
    641       if (bDataBind)
    642         break;
    643     }
    644     findObjects.clear();
    645 
    646     nNodes = pdfium::CollectionSize<int32_t>(retObjects);
    647     if (nNodes < 1) {
    648       if (dwStyles & XFA_RESOLVENODE_CreateNode) {
    649         bNextCreate = true;
    650         if (!m_ResolveProcessor->GetNodeHelper()->m_pCreateParent) {
    651           m_ResolveProcessor->GetNodeHelper()->m_pCreateParent =
    652               ToNode(rndFind.m_CurObject);
    653           m_ResolveProcessor->GetNodeHelper()->m_iCreateCount = 1;
    654         }
    655         bool bCreate =
    656             m_ResolveProcessor->GetNodeHelper()->ResolveNodes_CreateNode(
    657                 rndFind.m_wsName, rndFind.m_wsCondition,
    658                 nStart == pdfium::base::checked_cast<int32_t>(
    659                               wsExpression.GetLength()),
    660                 this);
    661         if (bCreate)
    662           continue;
    663       }
    664       break;
    665     }
    666 
    667     findObjects =
    668         std::vector<CXFA_Object*>(retObjects.begin(), retObjects.end());
    669     rndFind.m_Objects.clear();
    670     if (nLevel == 0)
    671       dwStyles &= ~(XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
    672 
    673     nLevel++;
    674   }
    675 
    676   if (!bNextCreate) {
    677     resolveNodeRS->dwFlags = rndFind.m_dwFlag;
    678     if (nNodes > 0) {
    679       resolveNodeRS->objects.insert(resolveNodeRS->objects.end(),
    680                                     findObjects.begin(), findObjects.end());
    681     }
    682     if (rndFind.m_dwFlag == XFA_ResolveNode_RSType_Attribute) {
    683       resolveNodeRS->pScriptAttribute = rndFind.m_pScriptAttribute;
    684       return 1;
    685     }
    686   }
    687   if (dwStyles & (XFA_RESOLVENODE_CreateNode | XFA_RESOLVENODE_Bind |
    688                   XFA_RESOLVENODE_BindNew)) {
    689     CXFA_NodeHelper* helper = m_ResolveProcessor->GetNodeHelper();
    690     if (helper->m_pCreateParent)
    691       resolveNodeRS->objects.push_back(helper->m_pCreateParent);
    692     else
    693       helper->CreateNode_ForCondition(rndFind.m_wsCondition);
    694 
    695     resolveNodeRS->dwFlags = helper->m_iCreateFlag;
    696     if (resolveNodeRS->dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
    697       if (helper->m_iCurAllStart != -1)
    698         resolveNodeRS->dwFlags = XFA_ResolveNode_RSType_CreateNodeMidAll;
    699     }
    700 
    701     if (!bNextCreate && (dwStyles & XFA_RESOLVENODE_CreateNode))
    702       resolveNodeRS->dwFlags = XFA_ResolveNode_RSType_ExistNodes;
    703 
    704     return !resolveNodeRS->objects.empty();
    705   }
    706   return nNodes > 0;
    707 }
    708 
    709 void CFXJSE_Engine::AddToCacheList(std::unique_ptr<CXFA_List> pList) {
    710   m_CacheList.push_back(std::move(pList));
    711 }
    712 
    713 CFXJSE_Value* CFXJSE_Engine::GetJSValueFromMap(CXFA_Object* pObject) {
    714   if (!pObject)
    715     return nullptr;
    716   if (pObject->IsNode())
    717     RunVariablesScript(pObject->AsNode());
    718 
    719   auto iter = m_mapObjectToValue.find(pObject);
    720   if (iter != m_mapObjectToValue.end())
    721     return iter->second.get();
    722 
    723   auto jsValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
    724   jsValue->SetObject(pObject, m_pJsClass);
    725 
    726   CFXJSE_Value* pValue = jsValue.get();
    727   m_mapObjectToValue.insert(std::make_pair(pObject, std::move(jsValue)));
    728   return pValue;
    729 }
    730 
    731 int32_t CFXJSE_Engine::GetIndexByName(CXFA_Node* refNode) {
    732   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
    733   return lpNodeHelper->GetIndex(refNode, XFA_LOGIC_Transparent,
    734                                 lpNodeHelper->NodeIsProperty(refNode), false);
    735 }
    736 
    737 int32_t CFXJSE_Engine::GetIndexByClassName(CXFA_Node* refNode) {
    738   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
    739   return lpNodeHelper->GetIndex(refNode, XFA_LOGIC_Transparent,
    740                                 lpNodeHelper->NodeIsProperty(refNode), true);
    741 }
    742 
    743 WideString CFXJSE_Engine::GetSomExpression(CXFA_Node* refNode) {
    744   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
    745   return lpNodeHelper->GetNameExpression(refNode, true, XFA_LOGIC_Transparent);
    746 }
    747 
    748 void CFXJSE_Engine::SetNodesOfRunScript(std::vector<CXFA_Node*>* pArray) {
    749   m_pScriptNodeArray = pArray;
    750 }
    751 
    752 void CFXJSE_Engine::AddNodesOfRunScript(CXFA_Node* pNode) {
    753   if (m_pScriptNodeArray && !pdfium::ContainsValue(*m_pScriptNodeArray, pNode))
    754     m_pScriptNodeArray->push_back(pNode);
    755 }
    756