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