1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/engine/quickjs/qjs_declarative_engine.h"
17
18 #include <cstdlib>
19
20 #include "native_engine/impl/quickjs/quickjs_native_engine.h"
21 #include "base/log/ace_trace.h"
22 #include "base/log/event_report.h"
23 #include "base/log/log.h"
24 #include "core/common/ace_view.h"
25 #include "core/common/container.h"
26 #include "core/common/container_scope.h"
27 #include "core/components/xcomponent/xcomponent_component_client.h"
28 #include "frameworks/bridge/declarative_frontend/engine/quickjs/modules/qjs_module_manager.h"
29 #include "frameworks/bridge/declarative_frontend/engine/quickjs/qjs_helpers.h"
30 #include "frameworks/bridge/declarative_frontend/frontend_delegate_declarative.h"
31 #include "frameworks/bridge/declarative_frontend/jsview/js_xcomponent.h"
32 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
33 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
34 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_utils.h"
35
36 namespace OHOS::Ace::Framework {
37
~QJSDeclarativeEngine()38 QJSDeclarativeEngine::~QJSDeclarativeEngine()
39 {
40 if (nativeEngine_ != nullptr) {
41 #if !defined(PREVIEW)
42 nativeEngine_->CancelCheckUVLoop();
43 #endif
44 nativeEngine_->DeleteEngine();
45 delete nativeEngine_;
46 }
47 if (engineInstance_ && engineInstance_->GetQJSRuntime()) {
48 JS_RunGC(engineInstance_->GetQJSRuntime());
49 }
50 }
51
Initialize(const RefPtr<FrontendDelegate> & delegate)52 bool QJSDeclarativeEngine::Initialize(const RefPtr<FrontendDelegate>& delegate)
53 {
54 LOGI("QJSDeclarativeEngine initialize");
55 JSRuntime* runtime = nullptr;
56 JSContext* context = nullptr;
57
58 // put JS_NewContext as early as possible to make stack_top in context
59 // closer to the top stack frame pointer of JS thread.
60 runtime = JS_NewRuntime();
61 if (runtime != nullptr) {
62 context = JS_NewContext(runtime);
63 }
64
65 engineInstance_ = AceType::MakeRefPtr<QJSDeclarativeEngineInstance>(delegate, instanceId_);
66 nativeEngine_ = new QuickJSNativeEngine(runtime, context, static_cast<void*>(this));
67 engineInstance_->SetNativeEngine(nativeEngine_);
68 bool res = engineInstance_->InitJSEnv(runtime, context, GetExtraNativeObject());
69 if (!res) {
70 LOGE("QJSDeclarativeEngine initialize failed: %{public}d", instanceId_);
71 return false;
72 }
73 SetPostTask(nativeEngine_);
74 #if !defined(PREVIEW)
75 nativeEngine_->CheckUVLoop();
76 #endif
77 if (delegate && delegate->GetAssetManager()) {
78 std::vector<std::string> packagePath = delegate->GetAssetManager()->GetLibPath();
79 if (!packagePath.empty()) {
80 auto qjsNativeEngine = static_cast<QuickJSNativeEngine*>(nativeEngine_);
81 qjsNativeEngine->SetPackagePath(packagePath);
82 }
83 }
84 RegisterWorker();
85
86 return true;
87 }
88
SetPostTask(NativeEngine * nativeEngine)89 void QJSDeclarativeEngine::SetPostTask(NativeEngine* nativeEngine)
90 {
91 LOGI("SetPostTask");
92 auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
93 auto&& postTask = [weakDelegate, nativeEngine = nativeEngine_, id = instanceId_](bool needSync) {
94 auto delegate = weakDelegate.Upgrade();
95 if (delegate == nullptr) {
96 LOGE("delegate is nullptr");
97 return;
98 }
99 delegate->PostJsTask([nativeEngine, needSync, id]() {
100 ContainerScope scope(id);
101 if (nativeEngine == nullptr) {
102 return;
103 }
104 nativeEngine->Loop(LOOP_NOWAIT, needSync);
105 });
106 };
107 nativeEngine_->SetPostTask(postTask);
108 }
109
RegisterInitWorkerFunc()110 void QJSDeclarativeEngine::RegisterInitWorkerFunc()
111 {
112 auto&& initWorkerFunc = [](NativeEngine* nativeEngine) {
113 LOGI("WorkerCore RegisterInitWorkerFunc called");
114 if (nativeEngine == nullptr) {
115 LOGE("nativeEngine is nullptr");
116 return;
117 }
118 auto qjsNativeEngine = static_cast<QuickJSNativeEngine*>(nativeEngine);
119 if (qjsNativeEngine == nullptr) {
120 LOGE("qjsNativeEngine is nullptr");
121 return;
122 }
123
124 JSContext* ctx = qjsNativeEngine->GetContext();
125 if (ctx == nullptr) {
126 LOGE("ctx is nullptr");
127 return;
128 }
129 // Note: default 256KB is not enough
130 JS_SetMaxStackSize(ctx, MAX_STACK_SIZE);
131
132 InitConsole(ctx);
133 };
134 nativeEngine_->SetInitWorkerFunc(initWorkerFunc);
135 }
136
RegisterAssetFunc()137 void QJSDeclarativeEngine::RegisterAssetFunc()
138 {
139 auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
140 auto&& assetFunc = [weakDelegate](const std::string& uri, std::vector<uint8_t>& content, std::string& ami) {
141 LOGI("WorkerCore RegisterAssetFunc called");
142 auto delegate = weakDelegate.Upgrade();
143 if (delegate == nullptr) {
144 LOGE("delegate is nullptr");
145 return;
146 }
147 delegate->GetResourceData(uri, content, ami);
148 };
149 nativeEngine_->SetGetAssetFunc(assetFunc);
150 }
151
RegisterWorker()152 void QJSDeclarativeEngine::RegisterWorker()
153 {
154 RegisterInitWorkerFunc();
155 RegisterAssetFunc();
156 }
157
LoadJs(const std::string & url,const RefPtr<JsAcePage> & page,bool isMainPage)158 void QJSDeclarativeEngine::LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage)
159 {
160 LOGD("QJSDeclarativeEngine LoadJs");
161 ACE_SCOPED_TRACE("QJSDeclarativeEngine::LoadJS");
162 ACE_DCHECK(engineInstance_);
163 engineInstance_->SetRunningPage(page);
164 JSContext* ctx = engineInstance_->GetQJSContext();
165 JS_SetContextOpaque(ctx, reinterpret_cast<void*>(AceType::RawPtr(engineInstance_)));
166 if (isMainPage) {
167 std::string commonsJsContent;
168 if (engineInstance_->GetDelegate()->GetAssetContent("commons.js", commonsJsContent)) {
169 auto commonsJsResult = QJSDeclarativeEngineInstance::EvalBuf(
170 ctx, commonsJsContent.c_str(), commonsJsContent.length(), "commons.js", JS_EVAL_TYPE_GLOBAL);
171 if (commonsJsResult == -1) {
172 LOGE("fail to execute load commonsjs script");
173 return;
174 }
175 }
176 std::string vendorsJsContent;
177 if (engineInstance_->GetDelegate()->GetAssetContent("vendors.js", vendorsJsContent)) {
178 auto vendorsJsResult = QJSDeclarativeEngineInstance::EvalBuf(
179 ctx, vendorsJsContent.c_str(), vendorsJsContent.length(), "vendors.js", JS_EVAL_TYPE_GLOBAL);
180 if (vendorsJsResult == -1) {
181 LOGE("fail to execute load vendorsjs script");
182 return;
183 }
184 }
185 std::string appjsContent;
186 if (!engineInstance_->GetDelegate()->GetAssetContent("app.js", appjsContent)) {
187 LOGE("js file load failed!");
188 }
189 std::string appMap;
190 if (engineInstance_->GetDelegate()->GetAssetContent("app.js.map", appMap)) {
191 page->SetAppMap(appMap);
192 } else {
193 LOGI("app map is missing!");
194 }
195 auto result = QJSDeclarativeEngineInstance::EvalBuf(
196 ctx, appjsContent.c_str(), appjsContent.length(), "app.js", JS_EVAL_TYPE_GLOBAL);
197 if (result == -1) {
198 LOGE("failed to execute Loadjs script");
199 } else {
200 CallAppFunc("onCreate", 0, nullptr);
201 }
202 }
203
204 std::string pageMap;
205 if (engineInstance_->GetDelegate()->GetAssetContent(url + ".map", pageMap)) {
206 page->SetPageMap(pageMap);
207 } else {
208 LOGI("the source map of page load failed!");
209 }
210
211 std::string jsContent;
212 if (!engineInstance_->GetDelegate()->GetAssetContent(url, jsContent)) {
213 LOGE("js file load failed!");
214 return;
215 }
216
217 if (jsContent.empty()) {
218 LOGE("js file load failed! url=[%{public}s]", url.c_str());
219 return;
220 }
221
222 JSValue compiled = engineInstance_->CompileSource(GetInstanceName(), url, jsContent.c_str(), jsContent.size());
223 if (JS_IsException(compiled)) {
224 LOGE("js compilation failed url=[%{public}s]", url.c_str());
225 QJSUtils::JsStdDumpErrorAce(
226 ctx, JsErrorType::LOAD_JS_BUNDLE_ERROR, instanceId_, page->GetUrl().c_str(), page, true);
227 return;
228 }
229 engineInstance_->ExecuteDocumentJS(compiled);
230 js_std_loop(engineInstance_->GetQJSContext());
231 }
232
LoadPageSource(const std::string & url)233 bool QJSDeclarativeEngine::LoadPageSource(const std::string& url)
234 {
235 LOGI("QJSDeclarativeEngine LoadPageSource");
236 ACE_SCOPED_TRACE("QJSDeclarativeEngine::LoadJS");
237 ACE_DCHECK(engineInstance_);
238 JSContext* ctx = engineInstance_->GetQJSContext();
239 JS_SetContextOpaque(ctx, reinterpret_cast<void*>(AceType::RawPtr(engineInstance_)));
240
241 std::string jsContent;
242 if (!engineInstance_->GetDelegate()->GetAssetContent(url, jsContent)) {
243 LOGE("js file load failed!");
244 return false;
245 }
246
247 if (jsContent.empty()) {
248 LOGE("js file load failed! url=[%{public}s]", url.c_str());
249 return false;
250 }
251
252 JSValue compiled = engineInstance_->CompileSource(GetInstanceName(), url, jsContent.c_str(), jsContent.size());
253 if (JS_IsException(compiled)) {
254 LOGE("js compilation failed url=[%{public}s]", url.c_str());
255 return false;
256 }
257 engineInstance_->ExecuteDocumentJS(compiled);
258 js_std_loop(engineInstance_->GetQJSContext());
259 return true;
260 }
261
LoadFaAppSource()262 bool QJSDeclarativeEngine::LoadFaAppSource()
263 {
264 LOGI("QJSDeclarativeEngine LoadFaAppSource");
265 ACE_SCOPED_TRACE("QJSDeclarativeEngine::LoadJS");
266 ACE_DCHECK(engineInstance_);
267 JSContext* ctx = engineInstance_->GetQJSContext();
268 std::string commonsJsContent;
269 if (engineInstance_->GetDelegate()->GetAssetContent("commons.js", commonsJsContent)) {
270 auto commonsJsResult = QJSDeclarativeEngineInstance::EvalBuf(
271 ctx, commonsJsContent.c_str(), commonsJsContent.length(), "commons.js", JS_EVAL_TYPE_GLOBAL);
272 if (commonsJsResult == -1) {
273 LOGE("fail to execute load commonsjs script");
274 return false;
275 }
276 }
277 std::string vendorsJsContent;
278 if (engineInstance_->GetDelegate()->GetAssetContent("vendors.js", vendorsJsContent)) {
279 auto vendorsJsResult = QJSDeclarativeEngineInstance::EvalBuf(
280 ctx, vendorsJsContent.c_str(), vendorsJsContent.length(), "vendors.js", JS_EVAL_TYPE_GLOBAL);
281 if (vendorsJsResult == -1) {
282 LOGE("fail to execute load vendorsjs script");
283 return false;
284 }
285 }
286 std::string appjsContent;
287 if (!engineInstance_->GetDelegate()->GetAssetContent("app.js", appjsContent)) {
288 LOGE("js file load failed!");
289 }
290
291 auto result = QJSDeclarativeEngineInstance::EvalBuf(
292 ctx, appjsContent.c_str(), appjsContent.length(), "app.js", JS_EVAL_TYPE_GLOBAL);
293 if (result == -1) {
294 LOGE("failed to execute Loadjs script");
295 } else {
296 CallAppFunc("onCreate", 0, nullptr);
297 }
298 return true;
299 }
300
301 #if defined(PREVIEW)
ReplaceJSContent(const std::string & url,const std::string componentName)302 void QJSDeclarativeEngine::ReplaceJSContent(const std::string& url, const std::string componentName)
303 {
304 auto* instance = static_cast<QJSDeclarativeEngineInstance*>(JS_GetContextOpaque(engineInstance_->GetQJSContext()));
305 if (instance == nullptr) {
306 LOGE("Can not cast Context to QJSDeclarativeEngineInstance object.");
307 return;
308 }
309 instance->SetPreviewFlag(true);
310 instance->SetRequiredComponent(componentName);
311
312 instance->GetDelegate()->Replace(url, "");
313 }
314 #endif
GetNewComponentWithJsCode(const std::string & jsCode,const std::string & viewID)315 RefPtr<Component> QJSDeclarativeEngine::GetNewComponentWithJsCode(const std::string& jsCode, const std::string& viewID)
316 {
317 #ifdef NG_BUILD
318 return nullptr;
319 #else
320 ViewStackProcessor::GetInstance()->ClearStack();
321 ViewStackProcessor::GetInstance()->PushKey(viewID);
322 bool result = engineInstance_->InitAceModules(jsCode.c_str(), jsCode.length(), "AddComponent");
323 ViewStackProcessor::GetInstance()->PopKey();
324 if (!result) {
325 LOGE("execute addComponent failed,script=[%{public}s]", jsCode.c_str());
326 return nullptr;
327 }
328 auto component = ViewStackProcessor::GetInstance()->GetNewComponent();
329 return component;
330 #endif
331 }
332
UpdateRunningPage(const RefPtr<JsAcePage> & page)333 void QJSDeclarativeEngine::UpdateRunningPage(const RefPtr<JsAcePage>& page)
334 {
335 ACE_DCHECK(engineInstance_);
336 engineInstance_->SetRunningPage(page);
337 js_std_loop(engineInstance_->GetQJSContext());
338 }
339
UpdateStagingPage(const RefPtr<JsAcePage> & page)340 void QJSDeclarativeEngine::UpdateStagingPage(const RefPtr<JsAcePage>& page)
341 {
342 ACE_DCHECK(engineInstance_);
343 engineInstance_->SetStagingPage(page);
344 js_std_loop(engineInstance_->GetQJSContext());
345 }
346
ResetStagingPage()347 void QJSDeclarativeEngine::ResetStagingPage()
348 {
349 ACE_DCHECK(engineInstance_);
350 auto runningPage = engineInstance_->GetRunningPage();
351 engineInstance_->ResetStagingPage(runningPage);
352 js_std_loop(engineInstance_->GetQJSContext());
353 }
354
DestroyPageInstance(int32_t pageId)355 void QJSDeclarativeEngine::DestroyPageInstance(int32_t pageId)
356 {
357 LOGE("Not implemented!");
358 js_std_loop(engineInstance_->GetQJSContext());
359 }
360
CallAppFunc(const std::string & appFuncName,int argc,JSValueConst * argv)361 void QJSDeclarativeEngine::CallAppFunc(const std::string& appFuncName, int argc, JSValueConst* argv)
362 {
363 JSContext* ctx = engineInstance_->GetQJSContext();
364 if (!ctx) {
365 LOGE("context is null");
366 return;
367 }
368 JSValue ret = JS_NULL;
369 CallAppFunc(appFuncName, argc, argv, ret);
370 js_std_loop(ctx);
371 JS_FreeValue(ctx, ret);
372 }
373
CallAppFunc(const std::string & appFuncName,int argc,JSValueConst * argv,JSValue & ret)374 void QJSDeclarativeEngine::CallAppFunc(const std::string& appFuncName, int argc, JSValueConst* argv, JSValue& ret)
375 {
376 JSContext* ctx = engineInstance_->GetQJSContext();
377 if (!ctx) {
378 LOGE("context is null");
379 return;
380 }
381 JSValue globalObj = JS_GetGlobalObject(ctx);
382 JSValue exportobj = JS_GetPropertyStr(ctx, globalObj, "exports");
383 JSValue defaultobj = JS_GetPropertyStr(ctx, exportobj, "default");
384
385 JSValue appFunc = JS_GetPropertyStr(ctx, defaultobj, appFuncName.c_str());
386 if (!JS_IsFunction(ctx, appFunc)) {
387 LOGE("cannot find %s function", appFuncName.c_str());
388 return;
389 }
390 ret = JS_Call(ctx, appFunc, defaultobj, argc, argv);
391 js_std_loop(ctx);
392 JS_FreeValue(ctx, appFunc);
393 JS_FreeValue(ctx, defaultobj);
394 JS_FreeValue(ctx, exportobj);
395 JS_FreeValue(ctx, globalObj);
396 }
397
DestroyApplication(const std::string & packageName)398 void QJSDeclarativeEngine::DestroyApplication(const std::string& packageName)
399 {
400 LOGI("Enter DestroyApplication: destroy, packageName %{public}s", packageName.c_str());
401 CallAppFunc("onDestroy", 0, nullptr);
402 js_std_loop(engineInstance_->GetQJSContext());
403 }
404
UpdateApplicationState(const std::string & packageName,Frontend::State state)405 void QJSDeclarativeEngine::UpdateApplicationState(const std::string& packageName, Frontend::State state)
406 {
407 LOGD("Enter UpdateApplicationState: destroy, packageName %{public}s", packageName.c_str());
408
409 if (state == Frontend::State::ON_SHOW) {
410 CallAppFunc("onShow", 0, nullptr);
411 } else if (state == Frontend::State::ON_HIDE) {
412 CallAppFunc("onHide", 0, nullptr);
413 }
414
415 js_std_loop(engineInstance_->GetQJSContext());
416 }
417
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)418 void QJSDeclarativeEngine::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
419 {
420 JSContext* ctx = engineInstance_->GetQJSContext();
421 if (!ctx) {
422 LOGE("context is null");
423 return;
424 }
425
426 JSValueConst callBackResult[] = { JS_NewBool(ctx, isShownInMultiWindow),
427 JS_ParseJSON(ctx, data.c_str(), data.length(), "") };
428 CallAppFunc("onWindowDisplayModeChanged", 2, callBackResult);
429
430 js_std_loop(engineInstance_->GetQJSContext());
431 }
432
OnConfigurationUpdated(const std::string & data)433 void QJSDeclarativeEngine::OnConfigurationUpdated(const std::string& data)
434 {
435 JSContext* ctx = engineInstance_->GetQJSContext();
436 if (!ctx) {
437 LOGE("context is null");
438 return;
439 }
440
441 JSValueConst callBackResult[] = { JS_ParseJSON(ctx, data.c_str(), data.length(), "") };
442 CallAppFunc("onConfigurationUpdated", 1, callBackResult);
443
444 js_std_loop(engineInstance_->GetQJSContext());
445 }
446
OnStartContinuation()447 bool QJSDeclarativeEngine::OnStartContinuation()
448 {
449 JSContext* ctx = engineInstance_->GetQJSContext();
450 if (!ctx) {
451 LOGE("context is null");
452 return false;
453 }
454 JSValue ret = JS_NULL;
455 CallAppFunc("onStartContinuation", 0, nullptr, ret);
456 std::string result = JS_ToCString(ctx, ret);
457 js_std_loop(engineInstance_->GetQJSContext());
458 return (result == "true");
459 }
460
OnCompleteContinuation(int32_t code)461 void QJSDeclarativeEngine::OnCompleteContinuation(int32_t code)
462 {
463 JSContext* ctx = engineInstance_->GetQJSContext();
464 if (!ctx) {
465 LOGE("context is null");
466 return;
467 }
468 JSValueConst callBackResult[] = { JS_NewInt32(ctx, code) };
469 CallAppFunc("onCompleteContinuation", 1, callBackResult);
470 js_std_loop(engineInstance_->GetQJSContext());
471 }
472
OnRemoteTerminated()473 void QJSDeclarativeEngine::OnRemoteTerminated()
474 {
475 JSContext* ctx = engineInstance_->GetQJSContext();
476 if (!ctx) {
477 LOGE("context is null");
478 return;
479 }
480 CallAppFunc("onRemoteTerminated", 0, nullptr);
481 js_std_loop(engineInstance_->GetQJSContext());
482 }
483
OnSaveData(std::string & data)484 void QJSDeclarativeEngine::OnSaveData(std::string& data)
485 {
486 JSContext* ctx = engineInstance_->GetQJSContext();
487 if (!ctx) {
488 LOGE("context is null");
489 return;
490 }
491 JSValue object = JS_NewObject(ctx);
492 JSValueConst callBackResult[] = { object };
493 JSValue ret = JS_NULL;
494 CallAppFunc("onSaveData", 1, callBackResult, ret);
495 if (JS_ToCString(ctx, ret) == std::string("true")) {
496 data = ScopedString::Stringify(ctx, object);
497 }
498 js_std_loop(engineInstance_->GetQJSContext());
499 }
500
OnRestoreData(const std::string & data)501 bool QJSDeclarativeEngine::OnRestoreData(const std::string& data)
502 {
503 JSContext* ctx = engineInstance_->GetQJSContext();
504 if (!ctx) {
505 LOGE("context is null");
506 return false;
507 }
508 JSValue jsonObj = JS_ParseJSON(ctx, data.c_str(), data.length(), "");
509 if (JS_IsUndefined(jsonObj) || JS_IsException(jsonObj)) {
510 LOGE("Parse json for restore data failed.");
511 return false;
512 }
513 JSValueConst callBackResult[] = { jsonObj };
514 JSValue ret = JS_NULL;
515 CallAppFunc("onRestoreData", 1, callBackResult, ret);
516 std::string result = JS_ToCString(ctx, ret);
517 js_std_loop(engineInstance_->GetQJSContext());
518 return (result == "true");
519 }
520
TimerCallback(const std::string & callbackId,const std::string & delay,bool isInterval)521 void QJSDeclarativeEngine::TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval)
522 {
523 // string with function source
524 LOGD("CallbackId %s", callbackId.c_str());
525 JSContext* ctx = engineInstance_->GetQJSContext();
526 QJSContext::Scope scp(ctx);
527
528 if (isInterval) {
529 TimerCallJs(callbackId, isInterval);
530 engineInstance_->GetDelegate()->WaitTimer(callbackId, delay, isInterval, false);
531 } else {
532 TimerCallJs(callbackId, isInterval);
533 JSContext* ctx = engineInstance_->GetQJSContext();
534 if (!ctx) {
535 LOGE("TimerCallback no context");
536 return;
537 }
538 ModuleManager::GetInstance()->RemoveCallbackFunc(ctx, std::stoi(callbackId), isInterval);
539 engineInstance_->GetDelegate()->ClearTimer(callbackId);
540 }
541 js_std_loop(engineInstance_->GetQJSContext());
542 }
543
TimerCallJs(const std::string & callbackId,bool isInterval)544 void QJSDeclarativeEngine::TimerCallJs(const std::string& callbackId, bool isInterval)
545 {
546 JSContext* ctx = engineInstance_->GetQJSContext();
547 if (!ctx) {
548 LOGE("TimerCallJs no context");
549 return;
550 }
551
552 JSValue jsFunc = ModuleManager::GetInstance()->GetCallbackFunc(std::stoi(callbackId), isInterval);
553 if (!JS_IsFunction(ctx, jsFunc)) {
554 LOGE("TimerCallJs is not func");
555 return;
556 }
557 std::vector<JSValue> jsargv = ModuleManager::GetInstance()->GetCallbackArray(std::stoi(callbackId), isInterval);
558 if (jsargv.empty()) {
559 JS_Call(ctx, jsFunc, JS_UNDEFINED, 0, nullptr);
560 } else {
561 JSValue* argv = new JSValue[jsargv.size()];
562 uint32_t index = 0;
563 while (index < jsargv.size()) {
564 argv[index] = jsargv[index];
565 ++index;
566 }
567 JS_Call(ctx, jsFunc, JS_UNDEFINED, jsargv.size(), argv);
568 }
569 js_std_loop(ctx);
570 }
571
MediaQueryCallback(const std::string & callbackId,const std::string & args)572 void QJSDeclarativeEngine::MediaQueryCallback(const std::string& callbackId, const std::string& args)
573 {
574 JsEngine::MediaQueryCallback(callbackId, args);
575 }
576
RequestAnimationCallback(const std::string & callbackId,uint64_t timeStamp)577 void QJSDeclarativeEngine::RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp)
578 {
579 LOGD("Enter RequestAnimationCallback");
580 }
581
JsCallback(const std::string & callbackId,const std::string & args)582 void QJSDeclarativeEngine::JsCallback(const std::string& callbackId, const std::string& args)
583 {
584 LOGD("Enter JSCallback");
585 }
586
FireAsyncEvent(const std::string & eventId,const std::string & param)587 void QJSDeclarativeEngine::FireAsyncEvent(const std::string& eventId, const std::string& param)
588 {
589 LOGW("QJSDeclarativeEngine FireAsyncEvent is unusable");
590 }
591
FireSyncEvent(const std::string & eventId,const std::string & param)592 void QJSDeclarativeEngine::FireSyncEvent(const std::string& eventId, const std::string& param)
593 {
594 LOGW("QJSDeclarativeEngine FireSyncEvent is unusable");
595 }
596
FireExternalEvent(const std::string & componentId,const uint32_t nodeId,const bool isDestroy)597 void QJSDeclarativeEngine::FireExternalEvent(
598 const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
599 {
600 #ifndef NG_BUILD
601 #ifdef XCOMPONENT_SUPPORTED
602 if (isDestroy) {
603 XComponentComponentClient::GetInstance().DeleteFromXcomponentsMapById(componentId);
604 XComponentClient::GetInstance().DeleteControllerFromJSXComponentControllersMap(componentId);
605 XComponentClient::GetInstance().DeleteFromNativeXcomponentsMapById(componentId);
606 XComponentClient::GetInstance().DeleteFromJsValMapById(componentId);
607 return;
608 }
609 std::tie(nativeXComponentImpl_, nativeXComponent_) =
610 XComponentClient::GetInstance().GetNativeXComponentFromXcomponentsMap(componentId);
611
612 RefPtr<XComponentComponent> xcomponent =
613 XComponentComponentClient::GetInstance().GetXComponentFromXcomponentsMap(componentId);
614 if (!xcomponent) {
615 LOGE("FireExternalEvent xcomponent is null.");
616 return;
617 }
618
619 void* nativeWindow = nullptr;
620 #ifdef OHOS_STANDARD_SYSTEM
621 nativeWindow = const_cast<void*>(xcomponent->GetNativeWindow());
622 #else
623 auto container = Container::Current();
624 if (!container) {
625 LOGE("FireExternalEvent Current container null");
626 return;
627 }
628 auto nativeView = static_cast<AceView*>(container->GetView());
629 if (!nativeView) {
630 LOGE("FireExternalEvent nativeView null");
631 return;
632 }
633 auto textureId = static_cast<uint64_t>(xcomponent->GetTextureId());
634 LOGE("FireExternalEvent textureId = %{public}" PRIu64, textureId);
635 nativeWindow = const_cast<void*>(nativeView->GetNativeWindowById(textureId));
636 #endif
637
638 if (!nativeWindow) {
639 LOGE("FireExternalEvent nativeWindow invalid");
640 return;
641 }
642 nativeXComponentImpl_->SetSurface(nativeWindow);
643 nativeXComponentImpl_->SetXComponentId(xcomponent->GetId());
644
645 auto nativeEngine = static_cast<QuickJSNativeEngine*>(nativeEngine_);
646 if (nativeEngine == nullptr) {
647 LOGE("nativeEngine is null");
648 return;
649 }
650
651 std::string args;
652 auto renderContext = nativeEngine->LoadModuleByName(
653 xcomponent->GetLibraryName(), true, args, OH_NATIVE_XCOMPONENT_OBJ, reinterpret_cast<void*>(nativeXComponent_));
654
655 JSRef<JSObject> obj = JSRef<JSObject>::Make(renderContext);
656 XComponentClient::GetInstance().AddJsValToJsValMap(componentId, obj);
657
658 auto task = [weak = WeakClaim(this), xcomponent]() {
659 auto pool = xcomponent->GetTaskPool();
660 if (!pool) {
661 return;
662 }
663 auto bridge = weak.Upgrade();
664 if (bridge) {
665 pool->NativeXComponentInit(
666 bridge->nativeXComponent_, AceType::WeakClaim(AceType::RawPtr(bridge->nativeXComponentImpl_)));
667 }
668 };
669
670 auto delegate = engineInstance_->GetDelegate();
671 if (!delegate) {
672 LOGE("Delegate is null");
673 return;
674 }
675 delegate->PostSyncTaskToPage(task);
676 #endif
677 #endif
678 }
679
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)680 void QJSDeclarativeEngine::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
681 {
682 ACE_DCHECK(engineInstance_);
683 engineInstance_->SetJsMessageDispatcher(dispatcher);
684 }
685
RunGarbageCollection()686 void QJSDeclarativeEngine::RunGarbageCollection()
687 {
688 ACE_DCHECK(engineInstance_);
689 engineInstance_->RunGarbageCollection();
690 }
691
GetGroupJsBridge()692 RefPtr<GroupJsBridge> QJSDeclarativeEngine::GetGroupJsBridge()
693 {
694 return AceType::MakeRefPtr<QuickJsGroupJsBridge>();
695 }
696
697 } // namespace OHOS::Ace::Framework
698