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