Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxfa / src / parser / xfa_script_imp.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../foxitlib.h"\r
8 #include "../common/xfa_utils.h"\r
9 #include "../common/xfa_object.h"\r
10 #include "../common/xfa_document.h"\r
11 #include "../common/xfa_parser.h"\r
12 #include "../common/xfa_script.h"\r
13 #include "../common/xfa_docdata.h"\r
14 #include "../common/xfa_doclayout.h"\r
15 #include "../common/xfa_debug.h"\r
16 #include "../common/xfa_localemgr.h"\r
17 #include "../common/xfa_fm2jsapi.h"\r
18 #include "xfa_debug_parser.h"\r
19 #include "xfa_script_imp.h"\r
20 #include "xfa_script_resolveprocessor.h"\r
21 #include "xfa_script_nodehelper.h"\r
22 CXFA_ScriptContext::CXFA_ScriptContext(CXFA_Document* pDocument)\r
23     : m_pDocument(pDocument), m_hJsRuntime(NULL), m_hJsContext(NULL), m_hJsClass(NULL)\r
24     , m_pEventParam(NULL), m_pResolveProcessor(NULL), m_eScriptType(XFA_SCRIPTLANGTYPE_Unkown)\r
25     , m_hFM2JSContext(NULL), m_pThisObject(NULL), m_pScriptNodeArray(NULL)\r
26     , m_dwBuiltInInFlags(0)\r
27     , m_eRunAtType(XFA_ATTRIBUTEENUM_Client)\r
28 {\r
29     FX_memset(&m_JsGlobalClass, 0, sizeof(FXJSE_CLASS));\r
30     FX_memset(&m_JsNormalClass, 0, sizeof(FXJSE_CLASS));\r
31 }\r
32 CXFA_ScriptContext::~CXFA_ScriptContext()\r
33 {\r
34     FX_POSITION ps = m_mapXFAToHValue.GetStartPosition();\r
35     while (ps) {\r
36         CXFA_Object* pXFAObj;\r
37         FXJSE_HVALUE pValue;\r
38         m_mapXFAToHValue.GetNextAssoc(ps, pXFAObj, pValue);\r
39         FXJSE_Value_Release(pValue);\r
40     }\r
41     m_mapXFAToHValue.RemoveAll();\r
42     ReleaseVariablesMap();\r
43     if(m_hFM2JSContext) {\r
44         XFA_FM2JS_ContextRelease(m_hFM2JSContext);\r
45         m_hFM2JSContext = NULL;\r
46     }\r
47     if(m_hJsContext) {\r
48         FXJSE_Context_Release(m_hJsContext);\r
49         m_hJsContext = NULL;\r
50     }\r
51     if(m_pResolveProcessor) {\r
52         delete m_pResolveProcessor;\r
53         m_pResolveProcessor = NULL;\r
54     }\r
55     m_upObjectArray.RemoveAll();\r
56     for (FX_INT32 i = 0; i < m_CacheListArray.GetSize(); i++) {\r
57         delete ((CXFA_NodeList*)m_CacheListArray[i]);\r
58     }\r
59     m_CacheListArray.RemoveAll();\r
60     if (m_dwBuiltInInFlags & XFA_JSBUILTIN_HasCount) {\r
61         FX_POSITION ps = m_JSBuiltInObjects.GetStartPosition();\r
62         while (ps) {\r
63             CFX_ByteString bsKey;\r
64             void* pValue = NULL;\r
65             m_JSBuiltInObjects.GetNextAssoc(ps, bsKey, pValue);\r
66             if (pValue) {\r
67                 FXJSE_Value_Release((FXJSE_HVALUE)pValue);\r
68             }\r
69         }\r
70         m_JSBuiltInObjects.RemoveAll();\r
71     }\r
72 }\r
73 void CXFA_ScriptContext::Initialize(FXJSE_HRUNTIME hRuntime)\r
74 {\r
75     m_hJsRuntime = hRuntime;\r
76     DefineJsContext();\r
77     DefineJsClass();\r
78     m_pResolveProcessor = FX_NEW CXFA_ResolveProcessor;\r
79 }\r
80 void CXFA_ScriptContext::Release()\r
81 {\r
82     delete this;\r
83 }\r
84 FX_BOOL CXFA_ScriptContext::RunScript(XFA_SCRIPTLANGTYPE eScriptType, FX_WSTR wsScript, FXJSE_HVALUE hRetValue, CXFA_Object* pThisObject )\r
85 {\r
86     CFX_ByteString btScript;\r
87     XFA_SCRIPTLANGTYPE eSaveType = m_eScriptType;\r
88     m_eScriptType = eScriptType;\r
89     if(eScriptType == XFA_SCRIPTLANGTYPE_Formcalc) {\r
90         if(!m_hFM2JSContext) {\r
91             m_hFM2JSContext = XFA_FM2JS_ContextCreate();\r
92             XFA_FM2JS_ContextInitialize(m_hFM2JSContext, m_hJsRuntime, m_hJsContext, m_pDocument);\r
93         }\r
94         CFX_WideTextBuf wsJavaScript;\r
95         CFX_WideString wsErrorInfo;\r
96         FX_INT32 iFlags = XFA_FM2JS_Translate(wsScript, wsJavaScript, wsErrorInfo);\r
97         if(iFlags) {\r
98             FXJSE_Value_SetUndefined(hRetValue);\r
99             return FALSE;\r
100         }\r
101         btScript = FX_UTF8Encode(wsJavaScript.GetBuffer(), wsJavaScript.GetLength());\r
102     } else {\r
103         if ((m_dwBuiltInInFlags & XFA_JSBUILTIN_Initialized) == 0) {\r
104             m_dwBuiltInInFlags = XFA_JSBUILTIN_Initialized;\r
105             FX_POSITION ps = m_JSBuiltInObjects.GetStartPosition();\r
106             if (ps) {\r
107                 FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(m_hJsContext);\r
108                 while (ps) {\r
109                     CFX_ByteString bsKey;\r
110                     void* pValue;\r
111                     m_JSBuiltInObjects.GetNextAssoc(ps, bsKey, pValue);\r
112                     FXJSE_HVALUE hProp = FXJSE_Value_Create(m_hJsRuntime);\r
113                     if (FXJSE_Value_GetObjectProp(hObject, bsKey, hProp)) {\r
114                         m_JSBuiltInObjects.SetAt(bsKey, hProp);\r
115                         FXJSE_Value_DeleteObjectProp(hObject, bsKey);\r
116                         m_dwBuiltInInFlags |= XFA_JSBUILTIN_HasCount;\r
117                     } else {\r
118                         m_JSBuiltInObjects.RemoveKey(bsKey);\r
119                         FXJSE_Value_Release(hProp);\r
120                     }\r
121                 }\r
122                 FXJSE_Value_Release(hObject);\r
123             }\r
124         }\r
125         btScript = FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength());\r
126     }\r
127     CXFA_Object *pOriginalObject = m_pThisObject;\r
128     m_pThisObject = pThisObject;\r
129     FXJSE_HVALUE pValue = pThisObject ? GetJSValueFromMap(pThisObject) : NULL;\r
130     FX_BOOL     bRet = FXJSE_ExecuteScript(m_hJsContext, btScript, hRetValue, pValue);\r
131     m_pThisObject = pOriginalObject;\r
132     m_eScriptType = eSaveType;\r
133     return bRet;\r
134 }\r
135 void CXFA_ScriptContext::GlobalPropertySetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
136 {\r
137     CXFA_Object* lpOrginalNode = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
138     CXFA_Document* pDoc = lpOrginalNode->GetDocument();\r
139     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pDoc->GetScriptContext();\r
140     CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(lpOrginalNode);\r
141     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
142     FX_DWORD dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Attributes;\r
143     CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject();\r
144     if(lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {\r
145         pRefNode = (CXFA_Node*)lpCurNode;\r
146     }\r
147     if(lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, TRUE)) {\r
148         return;\r
149     }\r
150     if(lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {\r
151         if (FXJSE_Value_IsUndefined(hValue)) {\r
152             FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue);\r
153             return;\r
154         }\r
155     }\r
156     IXFA_Notify* pNotify = pDoc->GetNotify();\r
157     if (!pNotify) {\r
158         return;\r
159     }\r
160     pNotify->GetDocProvider()->SetGlobalProperty(pNotify->GetHDOC(), szPropName, hValue);\r
161 }\r
162 FX_BOOL CXFA_ScriptContext::QueryNodeByFlag(CXFA_Node* refNode, FX_WSTR propname, FXJSE_HVALUE hValue, FX_DWORD dwFlag,  FX_BOOL bSetting)\r
163 {\r
164     XFA_RESOLVENODE_RS resolveRs;\r
165     FX_INT32 iRet = ResolveObjects(refNode, propname, resolveRs, dwFlag);\r
166     FX_BOOL bResult = FALSE;\r
167     if (iRet > 0) {\r
168         bResult = TRUE;\r
169         if(resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Nodes) {\r
170             FXJSE_HVALUE pValue = GetJSValueFromMap(resolveRs.nodes[0]);\r
171             FXJSE_Value_Set(hValue, pValue);\r
172         } else if(resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Attribute) {\r
173             XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = resolveRs.pScriptAttribute;\r
174             if(lpAttributeInfo) {\r
175                 (resolveRs.nodes[0]->*(lpAttributeInfo->lpfnCallback))(hValue, bSetting, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);\r
176             }\r
177         }\r
178     }\r
179     return bResult;\r
180 }\r
181 void CXFA_ScriptContext::GlobalPropertyGetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
182 {\r
183     CXFA_Object* pOrginalObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
184     CXFA_Document* pDoc = pOrginalObject->GetDocument();\r
185     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pDoc->GetScriptContext();\r
186     CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(pOrginalObject);\r
187     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
188     if (lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Formcalc) {\r
189         if(szPropName == FX_BSTRC(FOXIT_XFA_FM2JS_FORMCALC_RUNTIME)) {\r
190             XFA_FM2JS_GlobalPropertyGetter(lpScriptContext->m_hFM2JSContext, hValue);\r
191             return;\r
192         }\r
193         FX_UINT32 uHashCode = FX_HashCode_String_GetW(wsPropName, wsPropName.GetLength());\r
194         if(uHashCode != XFA_HASHCODE_Layout) {\r
195             CXFA_Object * pObject = lpScriptContext->GetDocument()->GetXFANode(uHashCode);\r
196             if (pObject) {\r
197                 FXJSE_Value_Set(hValue, lpScriptContext->GetJSValueFromMap(pObject));\r
198                 return;\r
199             }\r
200         }\r
201     }\r
202     FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Attributes;\r
203     CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject();\r
204     if(pOrginalObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {\r
205         pRefNode = (CXFA_Node*)lpCurNode;\r
206     }\r
207     if(lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, FALSE)) {\r
208         return;\r
209     }\r
210     dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings;\r
211     if(lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, FALSE)) {\r
212         return;\r
213     }\r
214     CXFA_Object* pScriptObject = lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);\r
215     if (pScriptObject && lpScriptContext->QueryVariableHValue((CXFA_Node *)pScriptObject, szPropName, hValue, TRUE)) {\r
216         return;\r
217     }\r
218     if (lpScriptContext->QueryBuiltinHValue(szPropName, hValue)) {\r
219         return;\r
220     }\r
221     IXFA_Notify* pNotify = pDoc->GetNotify();\r
222     if (!pNotify) {\r
223         return;\r
224     }\r
225     pNotify->GetDocProvider()->GetGlobalProperty(pNotify->GetHDOC(), szPropName, hValue);\r
226 }\r
227 void CXFA_ScriptContext::NormalPropertyGetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
228 {\r
229     CXFA_Object* pOrginalObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
230     if(pOrginalObject == NULL) {\r
231         FXJSE_Value_SetUndefined(hValue);\r
232         return;\r
233     }\r
234     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
235     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext();\r
236     CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject);\r
237     if(wsPropName == FX_WSTRC(L"xfa")) {\r
238         FXJSE_HVALUE pValue = lpScriptContext->GetJSValueFromMap(lpScriptContext->GetDocument()->GetRoot());\r
239         FXJSE_Value_Set(hValue, pValue);\r
240         return;\r
241     }\r
242     FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Attributes;\r
243     FX_BOOL bRet = lpScriptContext->QueryNodeByFlag((CXFA_Node *)pObject, wsPropName, hValue, dwFlag, FALSE);\r
244     if(bRet) {\r
245         return;\r
246     }\r
247     if (pObject == lpScriptContext->GetThisObject() || (lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Javascript && !lpScriptContext->IsStrictScopeInJavaScript())) {\r
248         dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings;\r
249         bRet = lpScriptContext->QueryNodeByFlag((CXFA_Node *)pObject, wsPropName, hValue, dwFlag, FALSE);\r
250     }\r
251     if(bRet) {\r
252         return;\r
253     }\r
254     CXFA_Object* pScriptObject = lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);\r
255     if (pScriptObject) {\r
256         bRet = lpScriptContext->QueryVariableHValue((CXFA_Node *)pScriptObject, szPropName, hValue, TRUE);\r
257     }\r
258     if (!bRet) {\r
259         FXJSE_Value_SetUndefined(hValue);\r
260     }\r
261 }\r
262 void CXFA_ScriptContext::NormalPropertySetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
263 {\r
264     CXFA_Object* pOrginalObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
265     if(pOrginalObject == NULL) {\r
266         return;\r
267     }\r
268     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext();\r
269     CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject);\r
270     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
271     XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = XFA_GetScriptAttributeByName(pObject->GetClassID(), wsPropName);\r
272     if(lpAttributeInfo) {\r
273         (pObject->*(lpAttributeInfo->lpfnCallback))(hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);\r
274     } else {\r
275         if(pObject->IsNode()) {\r
276             if(wsPropName.GetAt(0) == '#') {\r
277                 wsPropName = wsPropName.Right(wsPropName.GetLength() - 1);\r
278             }\r
279             CXFA_Node* pNode = (CXFA_Node*)pObject;\r
280             CXFA_Node *pPropOrChild = NULL;\r
281             XFA_LPCELEMENTINFO lpElementInfo =  XFA_GetElementByName(wsPropName);\r
282             if (lpElementInfo) {\r
283                 pPropOrChild = pNode->GetProperty(0, lpElementInfo->eName);\r
284             } else {\r
285                 pPropOrChild = pNode->GetFirstChildByName(wsPropName);\r
286             }\r
287             if (pPropOrChild) {\r
288                 CFX_WideString wsDefaultName = FX_WSTRC(L"{default}");\r
289                 XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = XFA_GetScriptAttributeByName(pPropOrChild->GetClassID(), wsDefaultName);\r
290                 if(lpAttributeInfo) {\r
291                     (pPropOrChild->*(lpAttributeInfo->lpfnCallback))(hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);\r
292                     return;\r
293                 }\r
294             }\r
295         }\r
296         CXFA_Object* pScriptObject = lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);\r
297         if (pScriptObject) {\r
298             lpScriptContext->QueryVariableHValue((CXFA_Node *)pScriptObject, szPropName, hValue, FALSE);\r
299         }\r
300     }\r
301 }\r
302 FX_INT32 CXFA_ScriptContext::NormalPropTypeGetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FX_BOOL bQueryIn)\r
303 {\r
304     CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
305     if(pObject == NULL) {\r
306         return FXJSE_ClassPropType_None;\r
307     }\r
308     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();\r
309     pObject = lpScriptContext->GetVariablesThis(pObject);\r
310     XFA_ELEMENT objElement = pObject->GetClassID();\r
311     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
312     if(XFA_GetMethodByName(objElement, wsPropName)) {\r
313         return FXJSE_ClassPropType_Method;\r
314     }\r
315     if (bQueryIn && !XFA_GetScriptAttributeByName(objElement, wsPropName)) {\r
316         return FXJSE_ClassPropType_None;\r
317     }\r
318     return FXJSE_ClassPropType_Property;\r
319 }\r
320 FX_INT32        CXFA_ScriptContext::GlobalPropTypeGetter(FXJSE_HOBJECT hObject, FX_BSTR szPropName, FX_BOOL bQueryIn)\r
321 {\r
322     CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
323     if(pObject == NULL) {\r
324         return FXJSE_ClassPropType_None;\r
325     }\r
326     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();\r
327     pObject = lpScriptContext->GetVariablesThis(pObject);\r
328     XFA_ELEMENT objElement = pObject->GetClassID();\r
329     CFX_WideString wsPropName = CFX_WideString::FromUTF8((FX_LPCSTR)szPropName.GetPtr(), szPropName.GetLength());\r
330     if(XFA_GetMethodByName(objElement, wsPropName)) {\r
331         return FXJSE_ClassPropType_Method;\r
332     }\r
333     return FXJSE_ClassPropType_Property;\r
334 }\r
335 void CXFA_ScriptContext::NormalMethodCall(FXJSE_HOBJECT hThis, FX_BSTR szFuncName, CFXJSE_Arguments &args)\r
336 {\r
337     CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hThis, NULL);\r
338     if(pObject == NULL) {\r
339         return;\r
340     }\r
341     CXFA_ScriptContext* lpScriptContext = (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();\r
342     pObject = lpScriptContext->GetVariablesThis(pObject);\r
343     CFX_WideString wsFunName = CFX_WideString::FromUTF8((FX_LPCSTR)szFuncName.GetPtr(), szFuncName.GetLength());\r
344     XFA_LPCMETHODINFO lpMethodInfo = XFA_GetMethodByName(pObject->GetClassID(), wsFunName);\r
345     if(NULL == lpMethodInfo) {\r
346         return;\r
347     }\r
348     (pObject->*(lpMethodInfo->lpfnCallback))(&args);\r
349 }\r
350 FX_BOOL CXFA_ScriptContext::IsStrictScopeInJavaScript()\r
351 {\r
352     return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping);\r
353 }\r
354 XFA_SCRIPTLANGTYPE CXFA_ScriptContext::GetType()\r
355 {\r
356     return m_eScriptType;\r
357 }\r
358 void CXFA_ScriptContext::DefineJsContext()\r
359 {\r
360     m_JsGlobalClass.constructor = NULL;\r
361     m_JsGlobalClass.name = "Root";\r
362     m_JsGlobalClass.propNum = 0;\r
363     m_JsGlobalClass.properties = NULL;\r
364     m_JsGlobalClass.methNum = 0;\r
365     m_JsGlobalClass.methods = NULL;\r
366     m_JsGlobalClass.dynPropGetter = CXFA_ScriptContext::GlobalPropertyGetter;\r
367     m_JsGlobalClass.dynPropSetter = CXFA_ScriptContext::GlobalPropertySetter;\r
368     m_JsGlobalClass.dynPropTypeGetter = CXFA_ScriptContext::GlobalPropTypeGetter;\r
369     m_JsGlobalClass.dynPropDeleter = NULL;\r
370     m_JsGlobalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall;\r
371     m_hJsContext = FXJSE_Context_Create(m_hJsRuntime, &m_JsGlobalClass, m_pDocument->GetRoot());\r
372     FXJSE_Context_EnableCompatibleMode(m_hJsContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS);\r
373 }\r
374 FXJSE_HCONTEXT CXFA_ScriptContext::CreateVariablesContext(CXFA_Node* pScriptNode, CXFA_Node* pSubform)\r
375 {\r
376     if(pScriptNode == NULL || pSubform == NULL) {\r
377         return NULL;\r
378     }\r
379     if(m_mapVariableToHValue.GetCount() == 0) {\r
380         m_JsGlobalVariablesClass.constructor = NULL;\r
381         m_JsGlobalVariablesClass.name = "XFAScriptObject";\r
382         m_JsGlobalVariablesClass.propNum = 0;\r
383         m_JsGlobalVariablesClass.properties = NULL;\r
384         m_JsGlobalVariablesClass.methNum = 0;\r
385         m_JsGlobalVariablesClass.methods = NULL;\r
386         m_JsGlobalVariablesClass.dynPropGetter = CXFA_ScriptContext::GlobalPropertyGetter;\r
387         m_JsGlobalVariablesClass.dynPropSetter = CXFA_ScriptContext::GlobalPropertySetter;\r
388         m_JsGlobalVariablesClass.dynPropTypeGetter = CXFA_ScriptContext::NormalPropTypeGetter;\r
389         m_JsGlobalVariablesClass.dynPropDeleter = NULL;\r
390         m_JsGlobalVariablesClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall;\r
391     }\r
392     CXFA_ThisProxy* lpVariableNode = FX_NEW CXFA_ThisProxy(pSubform, pScriptNode);\r
393     FXJSE_HCONTEXT hVariablesContext = FXJSE_Context_Create(m_hJsRuntime, &m_JsGlobalVariablesClass, (CXFA_Object*)lpVariableNode);\r
394     FXJSE_Context_EnableCompatibleMode(hVariablesContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS);\r
395     m_mapVariableToHValue.SetAt(pScriptNode, hVariablesContext);\r
396     return hVariablesContext;\r
397 }\r
398 CXFA_Object* CXFA_ScriptContext::GetVariablesThis(CXFA_Object* pObject,  FX_BOOL bScriptNode)\r
399 {\r
400     if(pObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {\r
401         return bScriptNode ? ((CXFA_ThisProxy*)pObject)->GetScriptNode() : ((CXFA_ThisProxy*)pObject)->GetThisNode();\r
402     }\r
403     return pObject;\r
404 }\r
405 FX_BOOL CXFA_ScriptContext::RunVariablesScript(CXFA_Node* pScriptNode)\r
406 {\r
407     if(pScriptNode == NULL) {\r
408         return FALSE;\r
409     }\r
410     if(pScriptNode->GetClassID() == XFA_ELEMENT_Script) {\r
411         CXFA_Node* pParent = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent);\r
412         if(!pParent || pParent->GetClassID() != XFA_ELEMENT_Variables) {\r
413             return FALSE;\r
414         }\r
415         if(m_mapVariableToHValue.GetValueAt(pScriptNode)) {\r
416             return TRUE;\r
417         }\r
418         CXFA_Node *pTextNode = pScriptNode->GetNodeItem(XFA_NODEITEM_FirstChild);\r
419         if (!pTextNode) {\r
420             return FALSE;\r
421         }\r
422         CFX_WideStringC wsScript;\r
423         if(!pTextNode->TryCData(XFA_ATTRIBUTE_Value, wsScript)) {\r
424             return FALSE;\r
425         }\r
426         CFX_ByteString btScript = FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength());\r
427         FXJSE_HVALUE hRetValue = FXJSE_Value_Create(m_hJsRuntime);\r
428         CXFA_Node* pThisObject = pParent->GetNodeItem(XFA_NODEITEM_Parent);\r
429         FXJSE_HCONTEXT hVariablesContext = CreateVariablesContext(pScriptNode, pThisObject);\r
430         CXFA_Object *pOriginalObject = m_pThisObject;\r
431         m_pThisObject = pThisObject;\r
432         FX_BOOL bRet = FXJSE_ExecuteScript(hVariablesContext, btScript, hRetValue);\r
433         m_pThisObject = pOriginalObject;\r
434         FXJSE_Value_Release(hRetValue);\r
435         return bRet;\r
436     }\r
437     return TRUE;\r
438 }\r
439 FX_BOOL CXFA_ScriptContext::QueryVariableHValue(CXFA_Node* pScriptNode, FX_BSTR szPropName, FXJSE_HVALUE hValue, FX_BOOL bGetter)\r
440 {\r
441     if(pScriptNode->GetClassID() != XFA_ELEMENT_Script) {\r
442         return FALSE;\r
443     }\r
444     CXFA_Node* variablesNode = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent);\r
445     if(!variablesNode || variablesNode->GetClassID() != XFA_ELEMENT_Variables) {\r
446         return FALSE;\r
447     }\r
448     FX_BOOL bRes = FALSE;\r
449     FX_LPVOID lpVariables = m_mapVariableToHValue.GetValueAt(pScriptNode);\r
450     if(lpVariables) {\r
451         FXJSE_HCONTEXT hVariableContext = (FXJSE_HCONTEXT)lpVariables;\r
452         FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext);\r
453         FXJSE_HVALUE hVariableValue = FXJSE_Value_Create(m_hJsRuntime);\r
454         if (!bGetter) {\r
455             FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue);\r
456             bRes = TRUE;\r
457         } else if(FXJSE_Value_ObjectHasOwnProp(hObject, szPropName, FALSE)) {\r
458             FXJSE_Value_GetObjectProp(hObject, szPropName, hVariableValue);\r
459             if(FXJSE_Value_IsFunction(hVariableValue)) {\r
460                 FXJSE_Value_SetFunctionBind(hValue, hVariableValue, hObject);\r
461             } else if (bGetter) {\r
462                 FXJSE_Value_Set(hValue, hVariableValue);\r
463             } else {\r
464                 FXJSE_Value_Set(hVariableValue, hValue);\r
465             }\r
466             bRes = TRUE;\r
467         }\r
468         FXJSE_Value_Release(hVariableValue);\r
469         FXJSE_Value_Release(hObject);\r
470     }\r
471     return bRes;\r
472 }\r
473 FX_BOOL CXFA_ScriptContext::QueryBuiltinHValue(FX_BSTR szPropName, FXJSE_HVALUE hValue)\r
474 {\r
475     void* pBuiltin = NULL;\r
476     if ((m_dwBuiltInInFlags & XFA_JSBUILTIN_HasCount) && m_JSBuiltInObjects.Lookup(szPropName, pBuiltin)) {\r
477         FXJSE_Value_Set(hValue, (FXJSE_HVALUE)pBuiltin);\r
478         return TRUE;\r
479     }\r
480     return FALSE;\r
481 }\r
482 void CXFA_ScriptContext::ReleaseVariablesMap()\r
483 {\r
484     FX_POSITION ps = m_mapVariableToHValue.GetStartPosition();\r
485     while (ps) {\r
486         CXFA_Object* pScriptNode;\r
487         FXJSE_HCONTEXT hVariableContext;\r
488         m_mapVariableToHValue.GetNextAssoc(ps, pScriptNode, hVariableContext);\r
489         FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext);\r
490         CXFA_Object* lpCurNode = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);\r
491         if(lpCurNode) {\r
492             delete (CXFA_ThisProxy*)lpCurNode;\r
493             lpCurNode = NULL;\r
494         }\r
495         FXJSE_Value_Release(hObject);\r
496         FXJSE_Context_Release(hVariableContext);\r
497         hVariableContext = NULL;\r
498     }\r
499     m_mapVariableToHValue.RemoveAll();\r
500 }\r
501 void CXFA_ScriptContext::DefineJsClass()\r
502 {\r
503     m_JsNormalClass.constructor = NULL;\r
504     m_JsNormalClass.name = "XFAObject";\r
505     m_JsNormalClass.propNum = 0;\r
506     m_JsNormalClass.properties = NULL;\r
507     m_JsNormalClass.methNum = 0;\r
508     m_JsNormalClass.methods = NULL;\r
509     m_JsNormalClass.dynPropGetter = CXFA_ScriptContext::NormalPropertyGetter;\r
510     m_JsNormalClass.dynPropSetter = CXFA_ScriptContext::NormalPropertySetter;\r
511     m_JsNormalClass.dynPropTypeGetter = CXFA_ScriptContext::NormalPropTypeGetter;\r
512     m_JsNormalClass.dynPropDeleter = NULL;\r
513     m_JsNormalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall;\r
514     m_hJsClass = FXJSE_DefineClass(m_hJsContext, &m_JsNormalClass);\r
515 }\r
516 FXJSE_HCLASS CXFA_ScriptContext::GetJseNormalClass()\r
517 {\r
518     return m_hJsClass;\r
519 }\r
520 void CXFA_ScriptContext::AddJSBuiltinObject(XFA_LPCJSBUILTININFO pBuitinObject)\r
521 {\r
522     if (m_dwBuiltInInFlags & XFA_JSBUILTIN_Initialized) {\r
523         return;\r
524     }\r
525     m_JSBuiltInObjects.SetAt(pBuitinObject->pName, (void*)pBuitinObject);\r
526 }\r
527 FX_INT32 CXFA_ScriptContext::ResolveObjects(CXFA_Object* refNode, FX_WSTR wsExpression, XFA_RESOLVENODE_RS& resolveNodeRS,  FX_DWORD dwStyles, CXFA_Node* bindNode)\r
528 {\r
529     if (wsExpression.IsEmpty()) {\r
530         return 0;\r
531     }\r
532     if (m_eScriptType != XFA_SCRIPTLANGTYPE_Formcalc || (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {\r
533         m_upObjectArray.RemoveAll();\r
534     }\r
535     if(refNode && (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings)) && refNode->IsNode()) {\r
536         m_upObjectArray.Add((CXFA_Node*)refNode);\r
537     }\r
538     FX_BOOL bNextCreate = FALSE;\r
539     if(dwStyles & XFA_RESOLVENODE_CreateNode) {\r
540         m_pResolveProcessor->GetNodeHelper()->XFA_SetCreateNodeType(bindNode);\r
541     }\r
542     m_pResolveProcessor->GetNodeHelper()->m_pCreateParent = NULL;\r
543     m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart = -1;\r
544     CXFA_ResolveNodesData rndFind;\r
545     FX_INT32 nStart = 0;\r
546     FX_INT32 nLevel = 0;\r
547     FX_INT32 nRet = -1;\r
548     rndFind.m_pSC = this;\r
549     CXFA_ObjArray findNodes;\r
550     if (refNode != NULL) {\r
551         findNodes.Add(refNode);\r
552     } else {\r
553         findNodes.Add(m_pDocument->GetRoot());\r
554     }\r
555     FX_INT32 nNodes = 0;\r
556     while (TRUE) {\r
557         nNodes = findNodes.GetSize();\r
558         FX_INT32 i = 0;\r
559         rndFind.m_dwStyles = dwStyles;\r
560         m_pResolveProcessor->m_iCurStart = nStart;\r
561         nStart = m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression, nStart, rndFind);\r
562         if (nStart < 1) {\r
563             if((dwStyles & XFA_RESOLVENODE_CreateNode) && !bNextCreate) {\r
564                 CXFA_Node* pDataNode = NULL;\r
565                 nStart = m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart;\r
566                 if(nStart != -1) {\r
567                     pDataNode = m_pDocument->GetNotBindNode(findNodes);\r
568                     if(pDataNode) {\r
569                         findNodes.RemoveAll();\r
570                         findNodes.Add(pDataNode);\r
571                         break;\r
572                     }\r
573                 } else {\r
574                     pDataNode = (CXFA_Node*)findNodes[0];\r
575                     findNodes.RemoveAll();\r
576                     findNodes.Add(pDataNode);\r
577                     break;\r
578                 }\r
579                 dwStyles |= XFA_RESOLVENODE_Bind;\r
580                 findNodes.RemoveAll();\r
581                 findNodes.Add(m_pResolveProcessor->GetNodeHelper()->m_pAllStartParent);\r
582                 continue;\r
583             } else {\r
584                 break;\r
585             }\r
586         }\r
587         if(bNextCreate) {\r
588             FX_BOOL bCreate = m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode(rndFind.m_wsName, rndFind.m_wsCondition, nStart == wsExpression.GetLength() ? TRUE : FALSE, this);\r
589             if(bCreate) {\r
590                 continue;\r
591             } else {\r
592                 break;\r
593             }\r
594         }\r
595         CXFA_ObjArray retNodes;\r
596         while (i < nNodes) {\r
597                         FX_BOOL bDataBind = FALSE;\r
598             if(((dwStyles & XFA_RESOLVENODE_Bind) || (dwStyles & XFA_RESOLVENODE_CreateNode)) && nNodes > 1) {\r
599                 CXFA_ResolveNodesData rndBind;\r
600                 m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression, nStart, rndBind);\r
601                 m_pResolveProcessor->XFA_ResolveNode_SetIndexDataBind(rndBind.m_wsCondition, i, nNodes);\r
602                                 bDataBind = TRUE;\r
603             }\r
604             rndFind.m_CurNode = findNodes[i ++];\r
605             rndFind.m_nLevel = nLevel;\r
606             rndFind.m_dwFlag = XFA_RESOVENODE_RSTYPE_Nodes;\r
607             nRet = m_pResolveProcessor->XFA_ResolveNodes(rndFind);\r
608             if (nRet < 1) {\r
609                 continue;\r
610             }\r
611             if (rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute && rndFind.m_pScriptAttribute && nStart < wsExpression.GetLength()) {\r
612                 FXJSE_HVALUE hValue = FXJSE_Value_Create(m_hJsRuntime);\r
613                 (rndFind.m_Nodes[0]->*(rndFind.m_pScriptAttribute->lpfnCallback))(hValue, FALSE, (XFA_ATTRIBUTE)rndFind.m_pScriptAttribute->eAttribute);\r
614                 rndFind.m_Nodes.SetAt(0, (CXFA_Object*)FXJSE_Value_ToObject(hValue, NULL));\r
615                 FXJSE_Value_Release(hValue);\r
616             }\r
617             FX_INT32 iSize = m_upObjectArray.GetSize();\r
618             if (iSize) {\r
619                 m_upObjectArray.RemoveAt(iSize - 1);\r
620             }\r
621             retNodes.Append(rndFind.m_Nodes);\r
622             rndFind.m_Nodes.RemoveAll();\r
623                         if(bDataBind){\r
624                                 break;\r
625                         }\r
626         }\r
627         findNodes.RemoveAll();\r
628         nNodes = retNodes.GetSize();\r
629         if (nNodes < 1) {\r
630             if(dwStyles & XFA_RESOLVENODE_CreateNode) {\r
631                 bNextCreate = TRUE;\r
632                 if(m_pResolveProcessor->GetNodeHelper()->m_pCreateParent == NULL) {\r
633                     m_pResolveProcessor->GetNodeHelper()->m_pCreateParent = (CXFA_Node*)rndFind.m_CurNode;\r
634                     m_pResolveProcessor->GetNodeHelper()->m_iCreateCount = 1;\r
635                 }\r
636                 FX_BOOL bCreate = m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode(rndFind.m_wsName, rndFind.m_wsCondition, nStart == wsExpression.GetLength() ? TRUE : FALSE, this);\r
637                 if(bCreate) {\r
638                     continue;\r
639                 } else {\r
640                     break;\r
641                 }\r
642             } else {\r
643                 break;\r
644             }\r
645         }\r
646         findNodes.Copy(retNodes);\r
647         rndFind.m_Nodes.RemoveAll();\r
648         if (nLevel == 0) {\r
649             dwStyles &= ~(XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);\r
650         }\r
651         nLevel ++;\r
652     }\r
653     if(!bNextCreate) {\r
654         resolveNodeRS.dwFlags = rndFind.m_dwFlag;\r
655         if (nNodes > 0) {\r
656             resolveNodeRS.nodes.Append(findNodes);\r
657         }\r
658         if(rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute) {\r
659             resolveNodeRS.pScriptAttribute = rndFind.m_pScriptAttribute;\r
660             return 1;\r
661         }\r
662     }\r
663     if(dwStyles & (XFA_RESOLVENODE_CreateNode | XFA_RESOLVENODE_Bind | XFA_RESOLVENODE_BindNew)) {\r
664         m_pResolveProcessor->XFA_ResolveNode_SetResultCreateNode(resolveNodeRS, rndFind.m_wsCondition);\r
665         if (!bNextCreate && (dwStyles & XFA_RESOLVENODE_CreateNode)) {\r
666             resolveNodeRS.dwFlags = XFA_RESOVENODE_RSTYPE_ExistNodes;\r
667         }\r
668         return resolveNodeRS.nodes.GetSize();\r
669     }\r
670     return nNodes;\r
671 }\r
672 FXJSE_HVALUE CXFA_ScriptContext::GetJSValueFromMap(CXFA_Object* pObject)\r
673 {\r
674     if (!pObject) {\r
675         return NULL;\r
676     }\r
677     if(pObject->IsNode()) {\r
678         RunVariablesScript((CXFA_Node*)pObject);\r
679     }\r
680     FX_LPVOID pValue = m_mapXFAToHValue.GetValueAt(pObject);\r
681     if(pValue == NULL) {\r
682         FXJSE_HVALUE jsHvalue = FXJSE_Value_Create(m_hJsRuntime);\r
683         FXJSE_Value_SetObject(jsHvalue, pObject, m_hJsClass);\r
684         m_mapXFAToHValue.SetAt(pObject, jsHvalue);\r
685         pValue = jsHvalue;\r
686     }\r
687     return (FXJSE_HVALUE)pValue;\r
688 }\r
689 FX_INT32        CXFA_ScriptContext::GetIndexByName(CXFA_Node* refNode)\r
690 {\r
691     CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();\r
692     return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent, lpNodeHelper->XFA_NodeIsProperty(refNode), FALSE);\r
693 }\r
694 FX_INT32        CXFA_ScriptContext::GetIndexByClassName(CXFA_Node* refNode)\r
695 {\r
696     CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();\r
697     return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent, lpNodeHelper->XFA_NodeIsProperty(refNode), TRUE);\r
698 }\r
699 void            CXFA_ScriptContext::GetSomExpression(CXFA_Node* refNode, CFX_WideString &wsExpression)\r
700 {\r
701     CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();\r
702     lpNodeHelper->XFA_GetNameExpression(refNode, wsExpression, TRUE, XFA_LOGIC_Transparent);\r
703 }\r
704 void CXFA_ScriptContext::SetNodesOfRunScript(CXFA_NodeArray *pArray)\r
705 {\r
706     m_pScriptNodeArray = pArray;\r
707 }\r
708 void CXFA_ScriptContext::AddNodesOfRunScript(const CXFA_NodeArray& nodes)\r
709 {\r
710     if (!m_pScriptNodeArray) {\r
711         return;\r
712     }\r
713     if (nodes.GetSize() > 0) {\r
714         m_pScriptNodeArray->Copy(nodes);\r
715     }\r
716 }\r
717 void CXFA_ScriptContext::AddNodesOfRunScript(CXFA_Node* pNode)\r
718 {\r
719     if (!m_pScriptNodeArray) {\r
720         return;\r
721     }\r
722     if (m_pScriptNodeArray->Find(pNode) == -1) {\r
723         m_pScriptNodeArray->Add(pNode);\r
724     }\r
725 }\r
726 IXFA_ScriptContext* XFA_ScriptContext_Create(CXFA_Document* pDocument)\r
727 {\r
728     return FX_NEW CXFA_ScriptContext(pDocument);\r
729 }\r
730 static const XFA_JSBUILTININFO gs_JSBUILTINData[] = {\r
731     {0x8108b9a9, (FX_LPCSTR)"Number"},\r
732     {0xe07e3fbe, (FX_LPCSTR)"Date"},\r
733 };\r
734 const FX_INT32 g_iJSBuiltinCount = sizeof(XFA_JSBUILTININFO) / sizeof(XFA_JSBUILTININFO);\r
735 XFA_LPCJSBUILTININFO XFA_GetJSBuiltinByHash(FX_UINT32 uHashCode)\r
736 {\r
737     FX_INT32 iStart = 0, iEnd = g_iJSBuiltinCount - 1, iMid;\r
738     do {\r
739         iMid = (iStart + iEnd) / 2;\r
740         XFA_LPCJSBUILTININFO pInfo = gs_JSBUILTINData + iMid;\r
741         if (uHashCode == pInfo->uUnicodeHash) {\r
742             return pInfo;\r
743         } else if (uHashCode < pInfo->uUnicodeHash) {\r
744             iEnd = iMid - 1;\r
745         } else {\r
746             iStart = iMid + 1;\r
747         }\r
748     } while (iStart <= iEnd);\r
749     return NULL;\r
750 }\r