Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfxjse_engine.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "fxjs/xfa/cfxjse_engine.h"
8
9#include <utility>
10
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"
17#include "fxjs/fxv8.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"
41
42using pdfium::fxjse::kClassTag;
43
45 kClassTag, // tag
46 "Root", // name
47 {}, // methods
48 CFXJSE_Engine::GlobalPropTypeGetter,
49 CFXJSE_Engine::GlobalPropertyGetter,
50 CFXJSE_Engine::GlobalPropertySetter,
51 CFXJSE_Engine::NormalMethodCall,
52};
53
55 kClassTag, // tag
56 "XFAObject", // name
57 {}, // methods
58 CFXJSE_Engine::NormalPropTypeGetter,
59 CFXJSE_Engine::NormalPropertyGetter,
60 CFXJSE_Engine::NormalPropertySetter,
61 CFXJSE_Engine::NormalMethodCall,
62};
63
65 kClassTag, // tag
66 "XFAScriptObject", // name
67 {}, // methods
68 CFXJSE_Engine::NormalPropTypeGetter,
69 CFXJSE_Engine::GlobalPropertyGetter,
70 CFXJSE_Engine::GlobalPropertySetter,
71 CFXJSE_Engine::NormalMethodCall,
72};
73
74namespace {
75
76const char kFormCalcRuntime[] = "pfm_rt";
77
78} // namespace
79
81
83 default;
84
86 const ResolveResult& that) = default;
87
89
90// static
92 const v8::FunctionCallbackInfo<v8::Value>& info) {
93 return ToObject(info.GetIsolate(), info.This());
94}
95
96// static
97CXFA_Object* CFXJSE_Engine::ToObject(v8::Isolate* pIsolate,
98 v8::Local<v8::Value> value) {
99 if (!value->IsObject())
100 return nullptr;
101
102 return ToObject(FXJSE_RetrieveObjectBinding(value.As<v8::Object>()));
103}
104
105// static.
107 CFXJSE_Value* pValue) {
108 return ToObject(pValue->ToHostObject(pIsolate));
109}
110
111// static
113 if (!pHostObj)
114 return nullptr;
115
116 CJX_Object* pJSObject = pHostObj->AsCJXObject();
117 return pJSObject ? pJSObject->GetXFAObject() : nullptr;
118}
119
120CFXJSE_Engine::CFXJSE_Engine(CXFA_Document* pDocument,
121 CJS_Runtime* fxjs_runtime)
122 : CFX_V8(fxjs_runtime->GetIsolate()),
128 nullptr)),
132 RemoveBuiltInObjs(m_JsContext.get());
133 m_JsContext->EnableCompatibleMode();
134
135 // Don't know if this can happen before we remove the builtin objs and set
136 // compatibility mode.
137 m_pJsClass =
138 CFXJSE_Class::Create(m_JsContext.get(), &kNormalClassDescriptor, false);
139}
140
142 // This is what ensures that the v8 object bound to a CJX_Object
143 // no longer retains that binding since it will outlive that object.
144 CFXJSE_ScopeUtil_IsolateHandleContext scope(GetJseContext());
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));
148 }
149}
150
152 CXFA_Node* pTarget,
153 CXFA_EventParam* pEventParam)
157 m_pEngine->m_pTarget = pTarget;
158 m_pEngine->m_eventParam = pEventParam;
159}
160
162 m_pEngine->m_pTarget = m_pPrevTarget;
163 m_pEngine->m_eventParam = m_pPrevEventParam;
164}
165
167 CXFA_Script::Type eScriptType,
168 WideStringView wsScript,
169 CXFA_Object* pThisObject) {
170 CFXJSE_ScopeUtil_IsolateHandleContext scope(GetJseContext());
171 AutoRestorer<CXFA_Script::Type> typeRestorer(&m_eScriptType);
172 m_eScriptType = eScriptType;
173
174 ByteString btScript;
175 if (eScriptType == CXFA_Script::Type::Formcalc) {
176 if (!m_FormCalcContext) {
177 m_FormCalcContext = std::make_unique<CFXJSE_FormCalcContext>(
178 GetIsolate(), m_JsContext.get(), m_pDocument.Get());
179 }
180 std::optional<WideTextBuffer> wsJavaScript =
181 CFXJSE_FormCalcContext::Translate(m_pDocument->GetHeap(), wsScript);
182 if (!wsJavaScript.has_value()) {
183 auto undefined_value = std::make_unique<CFXJSE_Value>();
184 undefined_value->SetUndefined(GetIsolate());
185 return CFXJSE_Context::ExecutionResult(false, std::move(undefined_value));
186 }
187 btScript = FX_UTF8Encode(wsJavaScript.value().AsStringView());
188 } else {
189 btScript = FX_UTF8Encode(wsScript);
190 }
191 AutoRestorer<cppgc::Persistent<CXFA_Object>> nodeRestorer(&m_pThisObject);
192 m_pThisObject = pThisObject;
193
194 v8::Local<v8::Object> pThisBinding;
195 if (pThisObject)
196 pThisBinding = GetOrCreateJSBindingFromMap(pThisObject);
197
198 IJS_Runtime::ScopedEventContext ctx(m_pSubordinateRuntime);
199 return m_JsContext->ExecuteScript(btScript.AsStringView(), pThisBinding);
200}
201
202bool CFXJSE_Engine::QueryNodeByFlag(CXFA_Node* refNode,
203 WideStringView propname,
204 v8::Local<v8::Value>* pValue,
205 Mask<XFA_ResolveFlag> dwFlag) {
206 if (!refNode)
207 return false;
208
209 std::optional<CFXJSE_Engine::ResolveResult> maybeResult =
210 ResolveObjects(refNode, propname, dwFlag);
211 if (!maybeResult.has_value())
212 return false;
213
214 if (maybeResult.value().type == ResolveResult::Type::kNodes) {
215 *pValue =
216 GetOrCreateJSBindingFromMap(maybeResult.value().objects.front().Get());
217 return true;
218 }
219 if (maybeResult.value().type == ResolveResult::Type::kAttribute &&
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);
225 }
226 return true;
227}
228
229bool CFXJSE_Engine::UpdateNodeByFlag(CXFA_Node* refNode,
230 WideStringView propname,
231 v8::Local<v8::Value> pValue,
232 Mask<XFA_ResolveFlag> dwFlag) {
233 if (!refNode)
234 return false;
235
236 std::optional<CFXJSE_Engine::ResolveResult> maybeResult =
237 ResolveObjects(refNode, propname, dwFlag);
238 if (!maybeResult.has_value())
239 return false;
240
241 if (maybeResult.value().type == ResolveResult::Type::kAttribute &&
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);
247 }
248 return true;
249}
250
251// static
252void CFXJSE_Engine::GlobalPropertySetter(v8::Isolate* pIsolate,
253 v8::Local<v8::Object> pObject,
254 ByteStringView szPropName,
255 v8::Local<v8::Value> pValue) {
256 CXFA_Object* pOriginalNode = ToObject(pIsolate, pObject);
257 CXFA_Document* pDoc = pOriginalNode->GetDocument();
258 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
259 CXFA_Node* pRefNode = ToNode(pScriptContext->GetThisObject());
260 if (pOriginalNode->IsThisProxy())
261 pRefNode = ToNode(pScriptContext->GetVariablesThis(pOriginalNode));
262
263 WideString wsPropName = WideString::FromUTF8(szPropName);
264 if (pScriptContext->UpdateNodeByFlag(
265 pRefNode, wsPropName.AsStringView(), pValue,
266 Mask<XFA_ResolveFlag>{
270 return;
271 }
272 if (pOriginalNode->IsThisProxy() && fxv8::IsUndefined(pValue)) {
273 fxv8::ReentrantDeleteObjectPropertyHelper(pScriptContext->GetIsolate(),
274 pObject, szPropName);
275 return;
276 }
277 CXFA_FFNotify* pNotify = pDoc->GetNotify();
278 if (!pNotify)
279 return;
280
281 CXFA_FFDoc* hDoc = pNotify->GetFFDoc();
282 auto* pCJSRuntime = static_cast<CJS_Runtime*>(hDoc->GetIJSRuntime());
283 if (!pCJSRuntime)
284 return;
285
286 IJS_Runtime::ScopedEventContext pContext(pCJSRuntime);
287 pCJSRuntime->SetValueByNameInGlobalObject(szPropName, pValue);
288}
289
290// static
291v8::Local<v8::Value> CFXJSE_Engine::GlobalPropertyGetter(
292 v8::Isolate* pIsolate,
293 v8::Local<v8::Object> pObject,
294 ByteStringView szPropName) {
295 CXFA_Object* pOriginalObject = ToObject(pIsolate, pObject);
296 CXFA_Document* pDoc = pOriginalObject->GetDocument();
297 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
298 WideString wsPropName = WideString::FromUTF8(szPropName);
299
300 // Assume failure.
301 v8::Local<v8::Value> pValue = fxv8::NewUndefinedHelper(pIsolate);
302
303 if (pScriptContext->GetType() == CXFA_Script::Type::Formcalc) {
304 if (szPropName == kFormCalcRuntime)
305 return pScriptContext->m_FormCalcContext->GlobalPropertyGetter();
306
307 XFA_HashCode uHashCode =
308 static_cast<XFA_HashCode>(FX_HashCode_GetW(wsPropName.AsStringView()));
309 if (uHashCode != XFA_HASHCODE_Layout) {
310 CXFA_Object* pObj =
311 pScriptContext->GetDocument()->GetXFAObject(uHashCode);
312 if (pObj)
313 return pScriptContext->GetOrCreateJSBindingFromMap(pObj);
314 }
315 }
316
317 CXFA_Node* pRefNode = ToNode(pScriptContext->GetThisObject());
318 if (pOriginalObject->IsThisProxy())
319 pRefNode = ToNode(pScriptContext->GetVariablesThis(pOriginalObject));
320
321 if (pScriptContext->QueryNodeByFlag(
322 pRefNode, wsPropName.AsStringView(), &pValue,
323 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren,
324 XFA_ResolveFlag::kProperties,
325 XFA_ResolveFlag::kAttributes})) {
326 return pValue;
327 }
328 if (pScriptContext->QueryNodeByFlag(
329 pRefNode, wsPropName.AsStringView(), &pValue,
330 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kParent,
331 XFA_ResolveFlag::kSiblings})) {
332 return pValue;
333 }
334
335 CXFA_Object* pScriptObject =
336 pScriptContext->GetVariablesScript(pOriginalObject);
337 if (pScriptObject && pScriptContext->QueryVariableValue(
338 CXFA_Script::FromNode(pScriptObject->AsNode()),
339 szPropName, &pValue)) {
340 return pValue;
341 }
342
343 CXFA_FFNotify* pNotify = pDoc->GetNotify();
344 if (!pNotify)
345 return pValue;
346
347 CXFA_FFDoc* hDoc = pNotify->GetFFDoc();
348 auto* pCJSRuntime = static_cast<CJS_Runtime*>(hDoc->GetIJSRuntime());
349 if (!pCJSRuntime)
350 return pValue;
351
352 IJS_Runtime::ScopedEventContext pContext(pCJSRuntime);
353 v8::Local<v8::Value> temp_value =
354 pCJSRuntime->GetValueByNameFromGlobalObject(szPropName);
355
356 return !temp_value.IsEmpty() ? temp_value : pValue;
357}
358
359// static
360FXJSE_ClassPropType CFXJSE_Engine::GlobalPropTypeGetter(
361 v8::Isolate* pIsolate,
362 v8::Local<v8::Object> pHolder,
363 ByteStringView szPropName,
364 bool bQueryIn) {
365 CXFA_Object* pObject = ToObject(pIsolate, pHolder);
366 if (!pObject)
368
369 CFXJSE_Engine* pScriptContext = pObject->GetDocument()->GetScriptContext();
370 pObject = pScriptContext->GetVariablesThis(pObject);
371 WideString wsPropName = WideString::FromUTF8(szPropName);
372 if (pObject->JSObject()->HasMethod(wsPropName))
374
376}
377
378// static
379v8::Local<v8::Value> CFXJSE_Engine::NormalPropertyGetter(
380 v8::Isolate* pIsolate,
381 v8::Local<v8::Object> pHolder,
382 ByteStringView szPropName) {
383 CXFA_Object* pOriginalObject = ToObject(pIsolate, pHolder);
384 if (!pOriginalObject)
385 return fxv8::NewUndefinedHelper(pIsolate);
386
387 CFXJSE_Engine* pScriptContext =
389
390 WideString wsPropName = WideString::FromUTF8(szPropName);
391 if (wsPropName.EqualsASCII("xfa")) {
392 return pScriptContext->GetOrCreateJSBindingFromMap(
393 pScriptContext->GetDocument()->GetRoot());
394 }
395
396 v8::Local<v8::Value> pReturnValue = fxv8::NewUndefinedHelper(pIsolate);
397 CXFA_Object* pObject = pScriptContext->GetVariablesThis(pOriginalObject);
398 CXFA_Node* pRefNode = ToNode(pObject);
399 if (pScriptContext->QueryNodeByFlag(
400 pRefNode, wsPropName.AsStringView(), &pReturnValue,
401 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren,
402 XFA_ResolveFlag::kProperties,
403 XFA_ResolveFlag::kAttributes})) {
404 return pReturnValue;
405 }
406 if (pObject == pScriptContext->GetThisObject() ||
407 (pScriptContext->GetType() == CXFA_Script::Type::Javascript &&
408 !pScriptContext->IsStrictScopeInJavaScript())) {
409 if (pScriptContext->QueryNodeByFlag(
410 pRefNode, wsPropName.AsStringView(), &pReturnValue,
411 Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kParent,
412 XFA_ResolveFlag::kSiblings})) {
413 return pReturnValue;
414 }
415 }
416 CXFA_Object* pScriptObject =
417 pScriptContext->GetVariablesScript(pOriginalObject);
418 if (!pScriptObject)
419 return pReturnValue;
420
421 if (pScriptContext->QueryVariableValue(
422 CXFA_Script::FromNode(pScriptObject->AsNode()), szPropName,
423 &pReturnValue)) {
424 return pReturnValue;
425 }
426 std::optional<XFA_SCRIPTATTRIBUTEINFO> info = XFA_GetScriptAttributeByName(
427 pObject->GetElementType(), wsPropName.AsStringView());
428 if (info.has_value()) {
429 (*info.value().callback)(pIsolate, pObject->JSObject(), &pReturnValue,
430 false, info.value().attribute);
431 return pReturnValue;
432 }
433
435 if (!pNotify)
436 return pReturnValue;
437
438 CXFA_FFDoc* hDoc = pNotify->GetFFDoc();
439 auto* pCJSRuntime = static_cast<CJS_Runtime*>(hDoc->GetIJSRuntime());
440 if (!pCJSRuntime)
441 return pReturnValue;
442
443 IJS_Runtime::ScopedEventContext pContext(pCJSRuntime);
444 v8::Local<v8::Value> temp_local =
445 pCJSRuntime->GetValueByNameFromGlobalObject(szPropName);
446
447 return !temp_local.IsEmpty() ? temp_local : pReturnValue;
448}
449
450// static
451void CFXJSE_Engine::NormalPropertySetter(v8::Isolate* pIsolate,
452 v8::Local<v8::Object> pHolder,
453 ByteStringView szPropName,
454 v8::Local<v8::Value> pValue) {
455 CXFA_Object* pOriginalObject = ToObject(pIsolate, pHolder);
456 if (!pOriginalObject)
457 return;
458
459 CFXJSE_Engine* pScriptContext =
461 if (pScriptContext->IsResolvingNodes())
462 return;
463
464 CXFA_Object* pObject = pScriptContext->GetVariablesThis(pOriginalObject);
465 WideString wsPropName = WideString::FromUTF8(szPropName);
466 WideStringView wsPropNameView = wsPropName.AsStringView();
467 std::optional<XFA_SCRIPTATTRIBUTEINFO> info =
468 XFA_GetScriptAttributeByName(pObject->GetElementType(), wsPropNameView);
469 if (info.has_value()) {
470 CJX_Object* jsObject = pObject->JSObject();
471 (*info.value().callback)(pIsolate, jsObject, &pValue, true,
472 info.value().attribute);
473 return;
474 }
475
476 if (pObject->IsNode()) {
477 if (wsPropNameView[0] == '#')
478 wsPropNameView = wsPropNameView.Last(wsPropNameView.GetLength() - 1);
479
480 CXFA_Node* pNode = ToNode(pObject);
481 CXFA_Node* pPropOrChild = nullptr;
482 XFA_Element eType = XFA_GetElementByName(wsPropNameView);
483 if (eType != XFA_Element::Unknown) {
484 pPropOrChild =
485 pNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eType);
486 } else {
487 pPropOrChild = pNode->GetFirstChildByName(wsPropNameView);
488 }
489
490 if (pPropOrChild) {
491 info = XFA_GetScriptAttributeByName(pPropOrChild->GetElementType(),
492 L"{default}");
493 if (info.has_value()) {
494 pPropOrChild->JSObject()->ScriptSomDefaultValue(pIsolate, &pValue, true,
496 return;
497 }
498 }
499 }
500
501 CXFA_Object* pScriptObject =
502 pScriptContext->GetVariablesScript(pOriginalObject);
503 if (pScriptObject) {
504 pScriptContext->UpdateVariableValue(
505 CXFA_Script::FromNode(pScriptObject->AsNode()), szPropName, pValue);
506 }
507}
508
509FXJSE_ClassPropType CFXJSE_Engine::NormalPropTypeGetter(
510 v8::Isolate* pIsolate,
511 v8::Local<v8::Object> pHolder,
512 ByteStringView szPropName,
513 bool bQueryIn) {
514 CXFA_Object* pObject = ToObject(pIsolate, pHolder);
515 if (!pObject)
517
518 CFXJSE_Engine* pScriptContext = pObject->GetDocument()->GetScriptContext();
519 pObject = pScriptContext->GetVariablesThis(pObject);
520 XFA_Element eType = pObject->GetElementType();
521 WideString wsPropName = WideString::FromUTF8(szPropName);
522 if (pObject->JSObject()->HasMethod(wsPropName))
524
525 if (bQueryIn) {
526 std::optional<XFA_SCRIPTATTRIBUTEINFO> maybe_info =
527 XFA_GetScriptAttributeByName(eType, wsPropName.AsStringView());
528 if (!maybe_info.has_value())
530 }
532}
533
534CJS_Result CFXJSE_Engine::NormalMethodCall(
535 const v8::FunctionCallbackInfo<v8::Value>& info,
536 const WideString& functionName) {
537 CXFA_Object* pObject = ToObject(info);
538 if (!pObject) {
539 return CJS_Result::Failure(WideString::FromASCII("no Holder() present."));
540 }
541 CFXJSE_Engine* pScriptContext = pObject->GetDocument()->GetScriptContext();
542 pObject = pScriptContext->GetVariablesThis(pObject);
543
544 v8::LocalVector<v8::Value> parameters(info.GetIsolate());
545 for (int i = 0; i < info.Length(); i++) {
546 parameters.push_back(info[i]);
547 }
548 return pObject->JSObject()->RunMethod(pScriptContext, functionName,
549 parameters);
550}
551
552bool CFXJSE_Engine::IsStrictScopeInJavaScript() {
553 return m_pDocument->is_strict_scoping();
554}
555
556CXFA_Script::Type CFXJSE_Engine::GetType() {
557 return m_eScriptType;
558}
559
561 m_upObjectArray.push_back(pNode);
562}
563
565 return !m_upObjectArray.empty() ? m_upObjectArray.back() : nullptr;
566}
567
568CFXJSE_Context* CFXJSE_Engine::CreateVariablesContext(CXFA_Script* pScriptNode,
569 CXFA_Node* pSubform) {
570 if (!pScriptNode || !pSubform)
571 return nullptr;
572
573 auto* proxy = cppgc::MakeGarbageCollected<CXFA_ThisProxy>(
574 pScriptNode->GetDocument()->GetHeap()->GetAllocationHandle(), pSubform,
575 pScriptNode);
576 auto pNewContext = CFXJSE_Context::Create(
577 GetIsolate(), &kVariablesClassDescriptor, proxy->JSObject(), proxy);
578 RemoveBuiltInObjs(pNewContext.get());
579 pNewContext->EnableCompatibleMode();
580 CFXJSE_Context* pResult = pNewContext.get();
581 m_mapVariableToContext[pScriptNode->JSObject()] = std::move(pNewContext);
582 return pResult;
583}
584
585CXFA_Object* CFXJSE_Engine::GetVariablesThis(CXFA_Object* pObject) {
586 CXFA_ThisProxy* pProxy = ToThisProxy(pObject);
587 return pProxy ? pProxy->GetThisNode() : pObject;
588}
589
590CXFA_Object* CFXJSE_Engine::GetVariablesScript(CXFA_Object* pObject) {
591 CXFA_ThisProxy* pProxy = ToThisProxy(pObject);
592 return pProxy ? pProxy->GetScriptNode() : pObject;
593}
594
595void CFXJSE_Engine::RunVariablesScript(CXFA_Script* pScriptNode) {
596 if (!pScriptNode)
597 return;
598
599 auto* pParent = CXFA_Variables::FromNode(pScriptNode->GetParent());
600 if (!pParent)
601 return;
602
603 auto it = m_mapVariableToContext.find(pScriptNode->JSObject());
604 if (it != m_mapVariableToContext.end() && it->second)
605 return;
606
607 CXFA_Node* pTextNode = pScriptNode->GetFirstChild();
608 if (!pTextNode)
609 return;
610
611 std::optional<WideString> wsScript =
612 pTextNode->JSObject()->TryCData(XFA_Attribute::Value, true);
613 if (!wsScript.has_value())
614 return;
615
616 ByteString btScript = wsScript->ToUTF8();
617 CXFA_Node* pThisObject = pParent->GetParent();
618 CFXJSE_Context* pVariablesContext =
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>());
624}
625
626CFXJSE_Context* CFXJSE_Engine::VariablesContextForScriptNode(
627 CXFA_Script* pScriptNode) {
628 if (!pScriptNode)
629 return nullptr;
630
631 auto* variablesNode = CXFA_Variables::FromNode(pScriptNode->GetParent());
632 if (!variablesNode)
633 return nullptr;
634
635 auto it = m_mapVariableToContext.find(pScriptNode->JSObject());
636 return it != m_mapVariableToContext.end() ? it->second.get() : nullptr;
637}
638
639bool CFXJSE_Engine::QueryVariableValue(CXFA_Script* pScriptNode,
640 ByteStringView szPropName,
641 v8::Local<v8::Value>* pValue) {
642 CFXJSE_Context* pVariableContext = VariablesContextForScriptNode(pScriptNode);
643 if (!pVariableContext)
644 return false;
645
646 v8::Local<v8::Object> pObject = pVariableContext->GetGlobalObject();
647 if (!fxv8::ReentrantHasObjectOwnPropertyHelper(GetIsolate(), pObject,
648 szPropName)) {
649 return false;
650 }
651
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())
658 *pValue = maybeFunc;
659 } else {
660 *pValue = hVariableValue;
661 }
662 return true;
663}
664
665bool CFXJSE_Engine::UpdateVariableValue(CXFA_Script* pScriptNode,
666 ByteStringView szPropName,
667 v8::Local<v8::Value> pValue) {
668 CFXJSE_Context* pVariableContext = VariablesContextForScriptNode(pScriptNode);
669 if (!pVariableContext)
670 return false;
671
672 v8::Local<v8::Object> pObject = pVariableContext->GetGlobalObject();
673 fxv8::ReentrantSetObjectOwnPropertyHelper(GetIsolate(), pObject, szPropName,
674 pValue);
675 return true;
676}
677
678void CFXJSE_Engine::RemoveBuiltInObjs(CFXJSE_Context* pContext) {
679 CFXJSE_ScopeUtil_IsolateHandleContext scope(GetJseContext());
680 v8::Local<v8::Object> pObject = pContext->GetGlobalObject();
681 fxv8::ReentrantDeleteObjectPropertyHelper(GetIsolate(), pObject, "Number");
682 fxv8::ReentrantDeleteObjectPropertyHelper(GetIsolate(), pObject, "Date");
683}
684
686 CXFA_Object* refObject,
687 WideStringView wsExpression,
688 Mask<XFA_ResolveFlag> dwStyles) {
689 return ResolveObjectsWithBindNode(refObject, wsExpression, dwStyles, nullptr);
690}
691
694 WideStringView wsExpression,
695 Mask<XFA_ResolveFlag> dwStyles,
696 CXFA_Node* bindNode) {
697 if (wsExpression.IsEmpty())
698 return std::nullopt;
699
700 AutoRestorer<bool> resolving_restorer(&m_bResolvingNodes);
701 m_bResolvingNodes = true;
702
703 const bool bParentOrSiblings =
704 !!(dwStyles & Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kParent,
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());
710
711 ResolveResult result;
712 bool bNextCreate = false;
713 if (dwStyles & XFA_ResolveFlag::kCreateNode)
714 m_NodeHelper->SetCreateNodeType(bindNode);
715
716 m_NodeHelper->m_pCreateParent = nullptr;
717 m_NodeHelper->m_iCurAllStart = -1;
718
720 int32_t nStart = 0;
721 int32_t nLevel = 0;
722
723 std::vector<cppgc::Member<CXFA_Object>> findObjects;
724 findObjects.emplace_back(refObject ? refObject : m_pDocument->GetRoot());
725 int32_t nNodes = 0;
726 CFXJSE_ScopeUtil_IsolateHandleContext scope(GetJseContext());
727 while (true) {
728 nNodes = fxcrt::CollectionSize<int32_t>(findObjects);
729 int32_t i = 0;
730 rndFind.m_dwStyles = dwStyles;
731 m_ResolveProcessor->SetCurStart(nStart);
732 nStart = m_ResolveProcessor->GetFilter(wsExpression, nStart, rndFind);
733 if (nStart < 1) {
734 if ((dwStyles & XFA_ResolveFlag::kCreateNode) && !bNextCreate) {
735 CXFA_Node* pDataNode = nullptr;
736 nStart = m_NodeHelper->m_iCurAllStart;
737 if (nStart != -1) {
738 pDataNode = m_pDocument->GetNotBindNode(findObjects);
739 if (pDataNode) {
740 findObjects.clear();
741 findObjects.emplace_back(pDataNode);
742 break;
743 }
744 } else {
745 pDataNode = findObjects.front()->AsNode();
746 findObjects.clear();
747 findObjects.emplace_back(pDataNode);
748 break;
749 }
750 dwStyles |= XFA_ResolveFlag::kBind;
751 findObjects.clear();
752 findObjects.emplace_back(m_NodeHelper->m_pAllStartParent.Get());
753 continue;
754 }
755 break;
756 }
757 if (bNextCreate) {
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)) {
762 continue;
763 }
764 break;
765 }
766 std::vector<cppgc::Member<CXFA_Object>> retObjects;
767 while (i < nNodes) {
768 bool bDataBind = false;
769 if (((dwStyles & XFA_ResolveFlag::kBind) ||
770 (dwStyles & XFA_ResolveFlag::kCreateNode)) &&
771 nNodes > 1) {
773 m_ResolveProcessor->GetFilter(wsExpression, nStart, rndBind);
774 i = m_ResolveProcessor->IndexForDataBind(rndBind.m_wsCondition, nNodes);
775 bDataBind = true;
776 }
777 rndFind.m_CurObject = findObjects[i++].Get();
778 rndFind.m_nLevel = nLevel;
780 if (!m_ResolveProcessor->Resolve(GetIsolate(), rndFind))
781 continue;
782
785 nStart < pdfium::checked_cast<int32_t>(wsExpression.GetLength())) {
786 v8::Local<v8::Value> pValue;
787 CJX_Object* jsObject = rndFind.m_Result.objects.front()->JSObject();
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);
793 }
794 }
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());
799 rndFind.m_Result.objects.clear();
800 if (bDataBind)
801 break;
802 }
803 findObjects.clear();
804
805 nNodes = fxcrt::CollectionSize<int32_t>(retObjects);
806 if (nNodes < 1) {
807 if (dwStyles & XFA_ResolveFlag::kCreateNode) {
808 bNextCreate = true;
809 if (!m_NodeHelper->m_pCreateParent) {
810 m_NodeHelper->m_pCreateParent = ToNode(rndFind.m_CurObject);
811 m_NodeHelper->m_iCreateCount = 1;
812 }
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)) {
817 continue;
818 }
819 }
820 break;
821 }
822
823 findObjects = std::move(retObjects);
824 rndFind.m_Result.objects.clear();
825 if (nLevel == 0) {
826 dwStyles.Clear(XFA_ResolveFlag::kParent);
827 dwStyles.Clear(XFA_ResolveFlag::kSiblings);
828 }
829 nLevel++;
830 }
831
832 if (!bNextCreate) {
833 result.type = rndFind.m_Result.type;
834 if (nNodes > 0) {
835 result.objects.insert(result.objects.end(), findObjects.begin(),
836 findObjects.end());
837 }
840 return result;
841 }
842 }
843 if ((dwStyles & XFA_ResolveFlag::kCreateNode) ||
844 (dwStyles & XFA_ResolveFlag::kBind) ||
845 (dwStyles & XFA_ResolveFlag::kBindNew)) {
846 if (m_NodeHelper->m_pCreateParent)
847 result.objects.emplace_back(m_NodeHelper->m_pCreateParent.Get());
848 else
849 m_NodeHelper->CreateNodeForCondition(rndFind.m_wsCondition);
850
851 result.type = m_NodeHelper->m_iCreateFlag;
853 if (m_NodeHelper->m_iCurAllStart != -1)
855 }
856
857 if (!bNextCreate && (dwStyles & XFA_ResolveFlag::kCreateNode))
859
860 if (result.objects.empty())
861 return std::nullopt;
862
863 return result;
864 }
865 if (nNodes == 0)
866 return std::nullopt;
867
868 return result;
869}
870
872 CXFA_Object* pObject) {
873 RunVariablesScript(CXFA_Script::FromNode(pObject->AsNode()));
874
875 CJX_Object* pCJXObject = pObject->JSObject();
876 auto iter = m_mapObjectToObject.find(pCJXObject);
877 if (iter != m_mapObjectToObject.end())
878 return v8::Local<v8::Object>::New(GetIsolate(), iter->second);
879
880 v8::Local<v8::Object> binding = pCJXObject->NewBoundV8Object(
881 GetIsolate(), m_pJsClass->GetTemplate(GetIsolate()));
882
883 m_mapObjectToObject[pCJXObject].Reset(GetIsolate(), binding);
884 return binding;
885}
886
889 m_pScriptNodeArray = pArray;
890}
891
893 if (m_pScriptNodeArray && !pdfium::Contains(*m_pScriptNodeArray, pNode))
894 m_pScriptNodeArray->emplace_back(pNode);
895}
896
897CXFA_Object* CFXJSE_Engine::ToXFAObject(v8::Local<v8::Value> obj) {
898 if (!fxv8::IsObject(obj))
899 return nullptr;
900
901 CFXJSE_HostObject* pHostObj =
902 FXJSE_RetrieveObjectBinding(obj.As<v8::Object>());
903 if (!pHostObj)
904 return nullptr;
905
906 CJX_Object* pJSObject = pHostObj->AsCJXObject();
907 return pJSObject ? pJSObject->GetXFAObject() : nullptr;
908}
909
911 v8::EscapableHandleScope scope(GetIsolate());
912 v8::Local<v8::Object> object = obj->JSObject()->NewBoundV8Object(
913 GetIsolate(), GetJseNormalClass()->GetTemplate(GetIsolate()));
914 return scope.Escape(object);
915}
fxcrt::ByteString ByteString
Definition bytestring.h:180
const FXJSE_CLASS_DESCRIPTOR kNormalClassDescriptor
const FXJSE_CLASS_DESCRIPTOR kGlobalClassDescriptor
const FXJSE_CLASS_DESCRIPTOR kVariablesClassDescriptor
XFA_ResolveFlag
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()
Definition fxjse.cpp:38
CFXJSE_Engine::ResolveResult m_Result
CFXJSE_ScopeUtil_IsolateHandleContext(CFXJSE_Context *pContext)
bool HasMethod(const WideString &func) const
CXFA_Object * GetXFAObject() const
Definition cjx_object.h:113
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
Definition cxfa_object.h:91
bool IsThisProxy() const
Definition cxfa_object.h:74
CXFA_Node * AsNode()
CJX_Object * JSObject()
Definition cxfa_object.h:81
CXFA_Document * GetDocument() const
Definition cxfa_object.h:48
bool IsNode() const
Definition cxfa_object.h:55
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
Definition widestring.h:111
CXFA_ThisProxy * ToThisProxy(CXFA_Object *pObj)
CXFA_Node * ToNode(CXFA_Object *pObj)
XFA_Attribute
Definition fxfa_basic.h:67
XFA_HashCode
Definition fxfa_basic.h:12
@ XFA_HASHCODE_Layout
Definition fxfa_basic.h:25
XFA_Element
Definition fxfa_basic.h:75
FXJSE_ClassPropType
Definition fxjse.h:31
Definition fxv8.h:22
bool IsUndefined(v8::Local< v8::Value > value)
Definition fxv8.cpp:20
const char kClassTag[]
Definition fxjse.cpp:18
fxcrt::ByteStringView ByteStringView
fxcrt::WideStringView WideStringView
XFA_ATTRIBUTE_CALLBACK callback
fxcrt::WideString WideString
Definition widestring.h:207