7#include "fxjs/xfa/cfxjse_engine.h"
11#include "core/fxcrt/autorestorer.h"
12#include "core/fxcrt/containers/contains.h"
13#include "core/fxcrt/fx_extension.h"
14#include "core/fxcrt/stl_util.h"
15#include "core/fxcrt/widetext_buffer.h"
16#include "fxjs/cjs_runtime.h"
18#include "fxjs/xfa/cfxjse_class.h"
19#include "fxjs/xfa/cfxjse_context.h"
20#include "fxjs/xfa/cfxjse_formcalc_context.h"
21#include "fxjs/xfa/cfxjse_isolatetracker.h"
22#include "fxjs/xfa/cfxjse_nodehelper.h"
23#include "fxjs/xfa/cfxjse_resolveprocessor.h"
24#include "fxjs/xfa/cfxjse_value.h"
25#include "fxjs/xfa/cjx_object.h"
26#include "v8/include/v8-function-callback.h"
27#include "v8/include/v8-function.h"
28#include "v8/include/v8-local-handle.h"
29#include "v8/include/v8-object.h"
30#include "xfa/fxfa/cxfa_eventparam.h"
31#include "xfa/fxfa/cxfa_ffdoc.h"
32#include "xfa/fxfa/cxfa_ffnotify.h"
33#include "xfa/fxfa/parser/cxfa_document.h"
34#include "xfa/fxfa/parser/cxfa_localemgr.h"
35#include "xfa/fxfa/parser/cxfa_node.h"
36#include "xfa/fxfa/parser/cxfa_object.h"
37#include "xfa/fxfa/parser/cxfa_thisproxy.h"
38#include "xfa/fxfa/parser/cxfa_variables.h"
39#include "xfa/fxfa/parser/xfa_basic_data.h"
40#include "xfa/fxfa/parser/xfa_utils.h"
48 CFXJSE_Engine::GlobalPropTypeGetter,
49 CFXJSE_Engine::GlobalPropertyGetter,
50 CFXJSE_Engine::GlobalPropertySetter,
51 CFXJSE_Engine::NormalMethodCall,
58 CFXJSE_Engine::NormalPropTypeGetter,
59 CFXJSE_Engine::NormalPropertyGetter,
60 CFXJSE_Engine::NormalPropertySetter,
61 CFXJSE_Engine::NormalMethodCall,
68 CFXJSE_Engine::NormalPropTypeGetter,
69 CFXJSE_Engine::GlobalPropertyGetter,
70 CFXJSE_Engine::GlobalPropertySetter,
71 CFXJSE_Engine::NormalMethodCall,
76const char kFormCalcRuntime[] =
"pfm_rt";
92 const v8::FunctionCallbackInfo<v8::Value>& info) {
93 return ToObject(info.GetIsolate(), info.This());
98 v8::Local<v8::Value> value) {
99 if (!value->IsObject())
102 return ToObject(FXJSE_RetrieveObjectBinding(value.As<v8::Object>()));
108 return ToObject(pValue->ToHostObject(pIsolate)
);
121 CJS_Runtime* fxjs_runtime)
122 :
CFX_V8(fxjs_runtime->GetIsolate()),
132 RemoveBuiltInObjs(m_JsContext.get());
133 m_JsContext->EnableCompatibleMode();
138 CFXJSE_Class::Create(m_JsContext.get(), &kNormalClassDescriptor,
false);
145 for (
const auto& pair : m_mapObjectToObject) {
146 const v8::Global<v8::Object>& binding = pair.second;
147 FXJSE_ClearObjectBinding(v8::Local<v8::Object>::New(GetIsolate(), binding));
157 m_pEngine->m_pTarget = pTarget;
158 m_pEngine->m_eventParam = pEventParam;
162 m_pEngine->m_pTarget = m_pPrevTarget;
163 m_pEngine->m_eventParam = m_pPrevEventParam;
167 CXFA_Script::
Type eScriptType,
172 m_eScriptType = eScriptType;
176 if (!m_FormCalcContext) {
177 m_FormCalcContext = std::make_unique<CFXJSE_FormCalcContext>(
178 GetIsolate(), m_JsContext.get(), m_pDocument.Get());
180 std::optional<WideTextBuffer> wsJavaScript =
181 CFXJSE_FormCalcContext::Translate(m_pDocument->GetHeap(), wsScript);
182 if (!wsJavaScript.has_value()) {
184 undefined_value->SetUndefined(GetIsolate());
187 btScript = FX_UTF8Encode(wsJavaScript.value().AsStringView());
189 btScript = FX_UTF8Encode(wsScript);
191 AutoRestorer<cppgc::Persistent<CXFA_Object>> nodeRestorer(&m_pThisObject);
192 m_pThisObject = pThisObject;
194 v8::Local<v8::Object> pThisBinding;
196 pThisBinding = GetOrCreateJSBindingFromMap(pThisObject);
199 return m_JsContext->ExecuteScript(btScript.AsStringView(), pThisBinding);
204 v8::Local<v8::Value>* pValue,
210 ResolveObjects(refNode, propname, dwFlag);
211 if (!maybeResult.has_value())
216 GetOrCreateJSBindingFromMap(maybeResult.value().objects.front().Get());
220 maybeResult.value().script_attribute.callback) {
221 CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
222 (*maybeResult.value().script_attribute.callback)(
223 GetIsolate(), jsObject, pValue,
false,
224 maybeResult.value().script_attribute.attribute);
231 v8::Local<v8::Value> pValue,
237 ResolveObjects(refNode, propname, dwFlag);
238 if (!maybeResult.has_value())
242 maybeResult.value().script_attribute.callback) {
243 CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
244 (*maybeResult.value().script_attribute.callback)(
245 GetIsolate(), jsObject, &pValue,
true,
246 maybeResult.value().script_attribute.attribute);
253 v8::Local<v8::Object> pObject,
255 v8::Local<v8::Value> pValue) {
256 CXFA_Object* pOriginalNode = ToObject(pIsolate, pObject);
261 pRefNode =
ToNode(pScriptContext->GetVariablesThis(pOriginalNode)
);
264 if (pScriptContext->UpdateNodeByFlag(
265 pRefNode, wsPropName.AsStringView(), pValue,
266 Mask<XFA_ResolveFlag>{
273 fxv8::ReentrantDeleteObjectPropertyHelper(pScriptContext->GetIsolate(),
274 pObject, szPropName);
287 pCJSRuntime->SetValueByNameInGlobalObject(szPropName, pValue);
292 v8::Isolate* pIsolate,
293 v8::Local<v8::Object> pObject,
295 CXFA_Object* pOriginalObject = ToObject(pIsolate, pObject);
301 v8::Local<v8::Value> pValue = fxv8::NewUndefinedHelper(pIsolate);
304 if (szPropName == kFormCalcRuntime)
305 return pScriptContext->m_FormCalcContext->GlobalPropertyGetter();
308 static_cast<
XFA_HashCode>(FX_HashCode_GetW(wsPropName.AsStringView()));
313 return pScriptContext->GetOrCreateJSBindingFromMap(pObj);
319 pRefNode =
ToNode(pScriptContext->GetVariablesThis(pOriginalObject)
);
321 if (pScriptContext->QueryNodeByFlag(
322 pRefNode, wsPropName.AsStringView(), &pValue,
323 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren,
324 XFA_ResolveFlag::kProperties,
325 XFA_ResolveFlag::kAttributes})) {
328 if (pScriptContext->QueryNodeByFlag(
329 pRefNode, wsPropName.AsStringView(), &pValue,
330 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kParent,
331 XFA_ResolveFlag::kSiblings})) {
336 pScriptContext->GetVariablesScript(pOriginalObject);
337 if (pScriptObject && pScriptContext->QueryVariableValue(
338 CXFA_Script::FromNode(pScriptObject->AsNode()),
339 szPropName, &pValue)) {
353 v8::Local<v8::Value> temp_value =
354 pCJSRuntime->GetValueByNameFromGlobalObject(szPropName);
356 return !temp_value.IsEmpty() ? temp_value : pValue;
361 v8::Isolate* pIsolate,
362 v8::Local<v8::Object> pHolder,
365 CXFA_Object* pObject = ToObject(pIsolate, pHolder);
370 pObject = pScriptContext->GetVariablesThis(pObject);
380 v8::Isolate* pIsolate,
381 v8::Local<v8::Object> pHolder,
383 CXFA_Object* pOriginalObject = ToObject(pIsolate, pHolder);
384 if (!pOriginalObject)
385 return fxv8::NewUndefinedHelper(pIsolate);
392 return pScriptContext->GetOrCreateJSBindingFromMap(
396 v8::Local<v8::Value> pReturnValue = fxv8::NewUndefinedHelper(pIsolate);
397 CXFA_Object* pObject = pScriptContext->GetVariablesThis(pOriginalObject);
399 if (pScriptContext->QueryNodeByFlag(
400 pRefNode, wsPropName.AsStringView(), &pReturnValue,
401 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren,
402 XFA_ResolveFlag::kProperties,
403 XFA_ResolveFlag::kAttributes})) {
408 !pScriptContext->IsStrictScopeInJavaScript())) {
409 if (pScriptContext->QueryNodeByFlag(
410 pRefNode, wsPropName.AsStringView(), &pReturnValue,
411 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kParent,
412 XFA_ResolveFlag::kSiblings})) {
417 pScriptContext->GetVariablesScript(pOriginalObject);
421 if (pScriptContext->QueryVariableValue(
422 CXFA_Script::FromNode(pScriptObject->AsNode()), szPropName,
427 pObject->GetElementType(), wsPropName.AsStringView());
428 if (info.has_value()) {
429 (*info.value().callback)(pIsolate, pObject->JSObject(), &pReturnValue,
430 false, info.value().attribute);
444 v8::Local<v8::Value> temp_local =
445 pCJSRuntime->GetValueByNameFromGlobalObject(szPropName);
447 return !temp_local.IsEmpty() ? temp_local : pReturnValue;
452 v8::Local<v8::Object> pHolder,
454 v8::Local<v8::Value> pValue) {
455 CXFA_Object* pOriginalObject = ToObject(pIsolate, pHolder);
456 if (!pOriginalObject)
464 CXFA_Object* pObject = pScriptContext->GetVariablesThis(pOriginalObject);
468 XFA_GetScriptAttributeByName(pObject->GetElementType(), wsPropNameView);
469 if (info.has_value()) {
471 (*info.value().callback)(pIsolate, jsObject, &pValue,
true,
472 info.value().attribute);
477 if (wsPropNameView[0] ==
'#')
478 wsPropNameView = wsPropNameView.Last(wsPropNameView.GetLength() - 1);
482 XFA_Element eType = XFA_GetElementByName(wsPropNameView);
485 pNode->JSObject()->GetOrCreateProperty<
CXFA_Node>(0, eType);
487 pPropOrChild = pNode->GetFirstChildByName(wsPropNameView);
493 if (info.has_value()) {
494 pPropOrChild->JSObject()->ScriptSomDefaultValue(pIsolate, &pValue,
true,
502 pScriptContext->GetVariablesScript(pOriginalObject);
504 pScriptContext->UpdateVariableValue(
510 v8::Isolate* pIsolate,
511 v8::Local<v8::Object> pHolder,
514 CXFA_Object* pObject = ToObject(pIsolate, pHolder);
519 pObject = pScriptContext->GetVariablesThis(pObject);
527 XFA_GetScriptAttributeByName(eType, wsPropName.AsStringView());
528 if (!maybe_info.has_value())
535 const v8::FunctionCallbackInfo<v8::Value>& info,
542 pObject = pScriptContext->GetVariablesThis(pObject);
544 v8::LocalVector<v8::Value> parameters(info.GetIsolate());
545 for (
int i = 0; i < info.Length(); i++) {
546 parameters.push_back(info[i]);
548 return pObject->JSObject()->RunMethod(pScriptContext, functionName,
553 return m_pDocument->is_strict_scoping();
557 return m_eScriptType;
561 m_upObjectArray.push_back(pNode);
565 return !m_upObjectArray.empty() ? m_upObjectArray.back() :
nullptr;
570 if (!pScriptNode || !pSubform)
573 auto* proxy = cppgc::MakeGarbageCollected<CXFA_ThisProxy>(
574 pScriptNode->GetDocument()->GetHeap()->GetAllocationHandle(), pSubform,
576 auto pNewContext = CFXJSE_Context::Create(
577 GetIsolate(), &kVariablesClassDescriptor, proxy->JSObject(), proxy);
578 RemoveBuiltInObjs(pNewContext.get());
579 pNewContext->EnableCompatibleMode();
581 m_mapVariableToContext[pScriptNode->JSObject()] = std::move(pNewContext);
595void CFXJSE_Engine::RunVariablesScript(CXFA_Script* pScriptNode) {
599 auto* pParent = CXFA_Variables
::FromNode(pScriptNode->GetParent()
);
603 auto it = m_mapVariableToContext.find(pScriptNode->JSObject());
604 if (it != m_mapVariableToContext.end() && it->second)
607 CXFA_Node* pTextNode = pScriptNode->GetFirstChild();
612 pTextNode->JSObject()->TryCData(XFA_Attribute::Value,
true);
613 if (!wsScript.has_value())
617 CXFA_Node* pThisObject = pParent->GetParent();
619 CreateVariablesContext(pScriptNode, pThisObject);
620 AutoRestorer<cppgc::Persistent<CXFA_Object>> nodeRestorer(&m_pThisObject);
621 m_pThisObject = pThisObject;
622 pVariablesContext->ExecuteScript(btScript.AsStringView(),
623 v8::Local<v8::Object>());
627 CXFA_Script* pScriptNode) {
631 auto* variablesNode = CXFA_Variables
::FromNode(pScriptNode->GetParent()
);
635 auto it = m_mapVariableToContext.find(pScriptNode->JSObject());
636 return it != m_mapVariableToContext.end() ? it->second.get() :
nullptr;
639bool CFXJSE_Engine::QueryVariableValue(CXFA_Script* pScriptNode,
641 v8::Local<v8::Value>* pValue) {
642 CFXJSE_Context* pVariableContext = VariablesContextForScriptNode(pScriptNode);
643 if (!pVariableContext)
646 v8::Local<v8::Object> pObject = pVariableContext->GetGlobalObject();
647 if (!fxv8::ReentrantHasObjectOwnPropertyHelper(GetIsolate(), pObject,
652 v8::Local<v8::Value> hVariableValue =
653 fxv8::ReentrantGetObjectPropertyHelper(GetIsolate(), pObject, szPropName);
654 if (fxv8::IsFunction(hVariableValue)) {
655 v8::Local<v8::Function> maybeFunc = CFXJSE_Value::NewBoundFunction(
656 GetIsolate(), hVariableValue.As<v8::Function>(), pObject);
657 if (!maybeFunc.IsEmpty())
660 *pValue = hVariableValue;
665bool CFXJSE_Engine::UpdateVariableValue(CXFA_Script* pScriptNode,
667 v8::Local<v8::Value> pValue) {
668 CFXJSE_Context* pVariableContext = VariablesContextForScriptNode(pScriptNode);
669 if (!pVariableContext)
672 v8::Local<v8::Object> pObject = pVariableContext->GetGlobalObject();
673 fxv8::ReentrantSetObjectOwnPropertyHelper(GetIsolate(), pObject, szPropName,
680 v8::Local<v8::Object> pObject = pContext->GetGlobalObject();
681 fxv8::ReentrantDeleteObjectPropertyHelper(GetIsolate(), pObject,
"Number");
682 fxv8::ReentrantDeleteObjectPropertyHelper(GetIsolate(), pObject,
"Date");
697 if (wsExpression.IsEmpty())
700 AutoRestorer<
bool> resolving_restorer(&m_bResolvingNodes);
701 m_bResolvingNodes =
true;
703 const bool bParentOrSiblings =
706 if (m_eScriptType != CXFA_Script::Type::Formcalc || bParentOrSiblings)
707 m_upObjectArray.clear();
708 if (refObject && refObject->IsNode() && bParentOrSiblings)
709 m_upObjectArray.push_back(refObject->AsNode());
712 bool bNextCreate =
false;
713 if (dwStyles & XFA_ResolveFlag::kCreateNode)
714 m_NodeHelper->SetCreateNodeType(bindNode);
716 m_NodeHelper->m_pCreateParent =
nullptr;
717 m_NodeHelper->m_iCurAllStart = -1;
723 std::vector<cppgc::Member<CXFA_Object>> findObjects;
724 findObjects.emplace_back(refObject ? refObject : m_pDocument->GetRoot());
728 nNodes = fxcrt::CollectionSize<int32_t>(findObjects);
730 rndFind.m_dwStyles = dwStyles;
731 m_ResolveProcessor->SetCurStart(nStart);
732 nStart = m_ResolveProcessor->GetFilter(wsExpression, nStart, rndFind);
736 nStart = m_NodeHelper->m_iCurAllStart;
738 pDataNode = m_pDocument->GetNotBindNode(findObjects);
741 findObjects.emplace_back(pDataNode);
745 pDataNode = findObjects.front()->AsNode();
747 findObjects.emplace_back(pDataNode);
752 findObjects.emplace_back(m_NodeHelper->m_pAllStartParent.Get());
758 int32_t checked_length =
759 pdfium::checked_cast<int32_t>(wsExpression.GetLength());
760 if (m_NodeHelper->CreateNode(rndFind.m_wsName, rndFind.m_wsCondition,
761 nStart == checked_length,
this)) {
766 std::vector<cppgc::Member<CXFA_Object>> retObjects;
768 bool bDataBind =
false;
773 m_ResolveProcessor->GetFilter(wsExpression, nStart, rndBind);
774 i = m_ResolveProcessor->IndexForDataBind(rndBind.m_wsCondition, nNodes);
777 rndFind.m_CurObject = findObjects[i++].Get();
780 if (!m_ResolveProcessor->Resolve(GetIsolate(), rndFind))
785 nStart <
pdfium::checked_cast<int32_t>(wsExpression.GetLength())) {
786 v8::Local<v8::Value> pValue;
788 (*rndFind.m_Result.script_attribute.callback)(
789 GetIsolate(), jsObject, &pValue,
false,
790 rndFind.m_Result.script_attribute.attribute);
791 if (!pValue.IsEmpty()) {
792 rndFind.m_Result.objects.front() = ToObject(GetIsolate(), pValue);
795 if (!m_upObjectArray.empty())
796 m_upObjectArray.pop_back();
797 retObjects.insert(retObjects.end(), rndFind.m_Result.objects.begin(),
798 rndFind.m_Result.objects.end());
805 nNodes = fxcrt::CollectionSize<int32_t>(retObjects);
809 if (!m_NodeHelper->m_pCreateParent) {
810 m_NodeHelper->m_pCreateParent = ToNode(rndFind.m_CurObject);
811 m_NodeHelper->m_iCreateCount = 1;
813 int32_t checked_length =
814 pdfium::checked_cast<int32_t>(wsExpression.GetLength());
815 if (m_NodeHelper->CreateNode(rndFind.m_wsName, rndFind.m_wsCondition,
816 nStart == checked_length,
this)) {
823 findObjects = std::move(retObjects);
835 result.objects.insert(result.objects.end(), findObjects.begin(),
846 if (m_NodeHelper->m_pCreateParent)
847 result.objects.emplace_back(m_NodeHelper->m_pCreateParent.Get());
849 m_NodeHelper->CreateNodeForCondition(rndFind.m_wsCondition);
851 result.type = m_NodeHelper->m_iCreateFlag;
853 if (m_NodeHelper->m_iCurAllStart != -1)
860 if (result.objects.empty())
876 auto iter = m_mapObjectToObject.find(pCJXObject);
877 if (iter != m_mapObjectToObject.end())
878 return v8::Local<v8::Object>::New(GetIsolate(), iter->second);
880 v8::Local<v8::Object> binding = pCJXObject->NewBoundV8Object(
881 GetIsolate(), m_pJsClass->GetTemplate(GetIsolate()));
883 m_mapObjectToObject[pCJXObject].Reset(GetIsolate(), binding);
889 m_pScriptNodeArray = pArray;
893 if (m_pScriptNodeArray && !pdfium::Contains(*m_pScriptNodeArray, pNode))
894 m_pScriptNodeArray->emplace_back(pNode);
898 if (!fxv8::IsObject(obj))
901 CFXJSE_HostObject* pHostObj =
902 FXJSE_RetrieveObjectBinding(obj.As<v8::Object>());
906 CJX_Object* pJSObject = pHostObj->AsCJXObject();
907 return pJSObject ? pJSObject->GetXFAObject() :
nullptr;
911 v8::EscapableHandleScope scope(GetIsolate());
912 v8::Local<v8::Object> object = obj->JSObject()->NewBoundV8Object(
913 GetIsolate(), GetJseNormalClass()->GetTemplate(GetIsolate()));
914 return scope.Escape(object);
fxcrt::ByteString ByteString
const FXJSE_CLASS_DESCRIPTOR kNormalClassDescriptor
const FXJSE_CLASS_DESCRIPTOR kGlobalClassDescriptor
const FXJSE_CLASS_DESCRIPTOR kVariablesClassDescriptor
EventParamScope(CFXJSE_Engine *pEngine, CXFA_Node *pTarget, CXFA_EventParam *pEventParam)
ResolveResult & operator=(const ResolveResult &that)
XFA_SCRIPTATTRIBUTEINFO script_attribute
ResolveResult(const ResolveResult &that)
bool IsResolvingNodes() const
CFXJSE_Engine(CXFA_Document *pDocument, CJS_Runtime *fxjs_runtime)
std::optional< ResolveResult > ResolveObjectsWithBindNode(CXFA_Object *refObject, WideStringView wsExpression, Mask< XFA_ResolveFlag > dwStyles, CXFA_Node *bindNode)
CXFA_Object * GetThisObject() const
CXFA_Script::Type GetType()
void AddNodesOfRunScript(CXFA_Node *pNode)
void SetNodesOfRunScript(std::vector< cppgc::Persistent< CXFA_Node > > *pArray)
friend class EventParamScope
static CXFA_Object * ToObject(v8::Isolate *pIsolate, CFXJSE_Value *pValue)
std::optional< ResolveResult > ResolveObjects(CXFA_Object *refObject, WideStringView wsExpression, Mask< XFA_ResolveFlag > dwStyles)
v8::Local< v8::Object > NewNormalXFAObject(CXFA_Object *obj)
CFXJSE_Context::ExecutionResult RunScript(CXFA_Script::Type eScriptType, WideStringView wsScript, CXFA_Object *pThisObject)
CXFA_Node * LastObjectFromUpArray()
~CFXJSE_Engine() override
static CXFA_Object * ToObject(CFXJSE_HostObject *pHostObj)
CXFA_Document * GetDocument() const
void AddObjectToUpArray(CXFA_Node *pNode)
v8::Local< v8::Object > GetOrCreateJSBindingFromMap(CXFA_Object *pObject)
virtual CJX_Object * AsCJXObject()
CFXJSE_Engine::ResolveResult m_Result
CFXJSE_ScopeUtil_IsolateHandleContext(CFXJSE_Context *pContext)
bool HasMethod(const WideString &func) const
CXFA_Object * GetXFAObject() const
CXFA_FFNotify * GetNotify() const
CFXJSE_Engine * GetScriptContext() const
CXFA_Object * GetXFAObject(XFA_HashCode wsNodeNameHash)
CXFA_Node * GetRoot() const
IJS_Runtime * GetIJSRuntime() const
CXFA_FFDoc * GetFFDoc() const
XFA_Element GetElementType() const
CXFA_Document * GetDocument() const
static CXFA_Script * FromNode(CXFA_Node *pNode)
CXFA_Script * GetScriptNode() const
CXFA_Node * GetThisNode() const
static CXFA_Variables * FromNode(CXFA_Node *pNode)
static WideString FromUTF8(ByteStringView str)
static WideString FromASCII(ByteStringView str)
bool EqualsASCII(ByteStringView that) const
CXFA_ThisProxy * ToThisProxy(CXFA_Object *pObj)
CXFA_Node * ToNode(CXFA_Object *pObj)
bool IsUndefined(v8::Local< v8::Value > value)
fxcrt::ByteStringView ByteStringView
fxcrt::WideStringView WideStringView
XFA_ATTRIBUTE_CALLBACK callback
fxcrt::WideString WideString