• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/js_frontend/engine/quickjs/qjs_engine.h"
17 
18 #include <algorithm>
19 #include <regex>
20 #include <string>
21 #include <unistd.h>
22 #include <unordered_map>
23 
24 #include "third_party/quickjs/message_server.h"
25 
26 #include "base/i18n/localization.h"
27 #include "base/json/json_util.h"
28 #include "base/log/ace_trace.h"
29 #include "base/log/event_report.h"
30 #include "base/log/log.h"
31 #include "base/utils/linear_map.h"
32 #include "base/utils/system_properties.h"
33 #include "base/utils/time_util.h"
34 #include "base/utils/utils.h"
35 #include "core/common/ace_application_info.h"
36 #include "core/common/container.h"
37 #include "core/common/container_scope.h"
38 #include "core/event/ace_event_helper.h"
39 #include "core/event/back_end_event_manager.h"
40 #include "frameworks/bridge/common/dom/dom_type.h"
41 #include "frameworks/bridge/common/media_query/media_query_info.h"
42 #include "frameworks/bridge/common/plugin_adapter/plugin_bridge.h"
43 #include "frameworks/bridge/common/utils/utils.h"
44 #include "frameworks/bridge/js_frontend/engine/common/js_api_perf.h"
45 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
46 #include "frameworks/bridge/js_frontend/engine/common/js_engine_loader.h"
47 #include "frameworks/bridge/js_frontend/engine/common/runtime_constants.h"
48 #include "frameworks/bridge/js_frontend/engine/quickjs/badge_bridge.h"
49 #include "frameworks/bridge/js_frontend/engine/quickjs/canvas_bridge.h"
50 #include "frameworks/bridge/js_frontend/engine/quickjs/chart_bridge.h"
51 #include "frameworks/bridge/js_frontend/engine/quickjs/clock_bridge.h"
52 #include "frameworks/bridge/js_frontend/engine/quickjs/component_api_bridge.h"
53 #include "frameworks/bridge/js_frontend/engine/quickjs/image_animator_bridge.h"
54 #include "frameworks/bridge/js_frontend/engine/quickjs/list_bridge.h"
55 #include "frameworks/bridge/js_frontend/engine/quickjs/offscreen_canvas_bridge.h"
56 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_group_js_bridge.h"
57 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_utils.h"
58 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_xcomponent_bridge.h"
59 #include "frameworks/bridge/js_frontend/engine/quickjs/stepper_bridge.h"
60 #include "frameworks/bridge/js_frontend/js_ace_page.h"
61 
62 extern const uint32_t js_framework_size;
63 extern const uint8_t js_framework[];
64 
65 namespace OHOS::Ace::Framework {
66 namespace {
67 
68 #ifndef ENABLE_JS_DEBUG
69 const char JS_MAIN_ENTRY[] = "___mainEntry___";
70 const char JS_EXT[] = ".js";
71 const char BIN_EXT[] = ".bin";
72 #endif
73 const char MAP_EXT[] = ".map";
74 constexpr int32_t CUSTOM_FULL_WINDOW_LENGTH = 3;
75 constexpr int32_t ARGS_FULL_WINDOW_LENGTH = 2;
76 constexpr int32_t ARGS_READ_RESOURCE_LENGTH = 2;
77 constexpr int32_t MAX_READ_TEXT_LENGTH = 4096;
78 const std::regex URI_PATTERN("^\\/([a-z0-9A-Z_]+\\/)*[a-z0-9A-Z_]+\\.?[a-z0-9A-Z_]*$");
79 
80 static int32_t globalNodeId = 100000;
81 std::map<const std::string, std::string> dataMap_;
82 
CallEvalBuf(JSContext * ctx,const char * buf,size_t bufLen,const char * filename,int32_t evalFlags,int32_t instanceId)83 int32_t CallEvalBuf(
84     JSContext* ctx, const char* buf, size_t bufLen, const char* filename, int32_t evalFlags, int32_t instanceId)
85 {
86     JSValue val = JS_Eval(ctx, buf, bufLen, filename, evalFlags);
87     int32_t ret = JS_CALL_SUCCESS;
88     if (JS_IsException(val)) {
89         LOGE("[Qjs Native] EvalBuf failed!");
90         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::EVAL_BUFFER_ERROR, instanceId);
91         ret = JS_CALL_FAIL;
92     }
93     JS_FreeValue(ctx, val);
94     js_std_loop(ctx);
95     return ret;
96 }
97 
CallReadObject(JSContext * ctx,const uint8_t * buf,size_t bufLen,bool persist=false,int32_t instanceId=0,const char * pageUrl=nullptr)98 JSValue CallReadObject(JSContext* ctx, const uint8_t* buf, size_t bufLen, bool persist = false, int32_t instanceId = 0,
99     const char* pageUrl = nullptr)
100 {
101     int32_t flags = persist ? (JS_READ_OBJ_ROM_DATA | JS_READ_OBJ_BYTECODE) : JS_READ_OBJ_BYTECODE;
102     JSValue obj = JS_ReadObject(ctx, buf, bufLen, flags);
103     if (JS_IsException(obj)) {
104         LOGE("[Qjs Native] ReadObject failed!");
105         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::READ_OBJECT_ERROR, instanceId, pageUrl);
106         return obj;
107     }
108     return JS_EvalFunction(ctx, obj);
109 }
110 
GetRunningPage(JSContext * ctx)111 RefPtr<JsAcePage> GetRunningPage(JSContext* ctx)
112 {
113     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
114     ACE_DCHECK(instance);
115     return instance->GetRunningPage();
116 }
117 
GetStagingPage(JSContext * ctx)118 RefPtr<JsAcePage> GetStagingPage(JSContext* ctx)
119 {
120     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
121     ACE_DCHECK(instance);
122     return instance->GetStagingPage();
123 }
124 
GetArrayValue(JSContext * ctx,JSValueConst arrayVal,std::string & result)125 void GetArrayValue(JSContext* ctx, JSValueConst arrayVal, std::string& result)
126 {
127     int32_t length = QJSUtils::JsGetArrayLength(ctx, arrayVal);
128     for (int32_t i = 0; i < length; ++i) {
129         if (i != 0) {
130             result.append(1, DOM_PICKER_SPLIT_ARRAY); // only need one char to split.
131         }
132         JSValue itemVal = JS_GetPropertyUint32(ctx, arrayVal, i);
133         if (JS_IsString(itemVal) || JS_IsNumber(itemVal) || JS_IsBool(itemVal)) {
134             ScopedString val(ctx, itemVal);
135             const char* itemStr = val.get();
136             result.append(itemStr);
137             JS_FreeValue(ctx, itemVal);
138             continue;
139         }
140         if (JS_IsArray(ctx, itemVal)) {
141             int32_t subLength = QJSUtils::JsGetArrayLength(ctx, itemVal);
142             for (int32_t j = 0; j < subLength; ++j) {
143                 if (j != 0) {
144                     result.append(1, DOM_PICKER_SPLIT_ITEM); // only need one char to split
145                 }
146                 JSValue subItemVal = JS_GetPropertyUint32(ctx, itemVal, j);
147                 ScopedString subVal(ctx, subItemVal);
148                 const char* subItemStr = subVal.get();
149                 result.append(subItemStr);
150                 JS_FreeValue(ctx, subItemVal);
151             }
152             JS_FreeValue(ctx, itemVal);
153             continue;
154         }
155         JS_FreeValue(ctx, itemVal);
156     }
157 }
158 
GetAttrImage(JSContext * ctx,JSValueConst valObject,ImageProperties & imageProperties)159 void GetAttrImage(JSContext* ctx, JSValueConst valObject, ImageProperties& imageProperties)
160 {
161     JSPropertyEnum* pTab = nullptr;
162     uint32_t len = 0;
163     if (!CheckAndGetJsProperty(ctx, valObject, &pTab, &len)) {
164         return;
165     }
166     for (uint32_t i = 0; i < len; ++i) {
167         const char* key = JS_AtomToCString(ctx, pTab[i].atom);
168         if (key == nullptr) {
169             JS_FreeAtom(ctx, pTab[i].atom);
170             LOGW("key is null. Ignoring!");
171             continue;
172         }
173         JSValue valItem = JS_GetProperty(ctx, valObject, pTab[i].atom);
174         if (JS_IsString(valItem) || JS_IsNumber(valItem) || JS_IsBool(valItem)) {
175             ScopedString styleVal(ctx, valItem);
176             const char* valStr = styleVal.get();
177             if (strcmp(key, "src") == 0) {
178                 imageProperties.src = valStr;
179             } else if (strcmp(key, "width") == 0) {
180                 imageProperties.width = StringToDimension(valStr);
181             } else if (strcmp(key, "height") == 0) {
182                 imageProperties.height = StringToDimension(valStr);
183             } else if (strcmp(key, "top") == 0) {
184                 imageProperties.top = StringToDimension(valStr);
185             } else if (strcmp(key, "left") == 0) {
186                 imageProperties.left = StringToDimension(valStr);
187             } else if (strcmp(key, "duration") == 0) {
188                 imageProperties.duration = StringToInt(valStr);
189             } else {
190                 LOGD("key : %{public}s unsupported. Ignoring!", key);
191             }
192         } else {
193             LOGD("value of unsupported type. Ignoring!");
194         }
195         JS_FreeAtom(ctx, pTab[i].atom);
196         JS_FreeCString(ctx, key);
197         JS_FreeValue(ctx, valItem);
198     }
199     js_free(ctx, pTab);
200 }
201 
GetAttrImages(JSContext * ctx,JSValueConst arrayVal,std::vector<ImageProperties> & images)202 void GetAttrImages(JSContext* ctx, JSValueConst arrayVal, std::vector<ImageProperties>& images)
203 {
204     int32_t length = QJSUtils::JsGetArrayLength(ctx, arrayVal);
205     for (int32_t i = 0; i < length; ++i) {
206         JSValue valArray = JS_GetPropertyUint32(ctx, arrayVal, i);
207         ImageProperties imageProperties;
208         if (JS_IsObject(valArray)) {
209             GetAttrImage(ctx, valArray, imageProperties);
210             images.push_back(imageProperties);
211         }
212         JS_FreeValue(ctx, valArray);
213     }
214 }
215 
SetDomAttributes(JSContext * ctx,JSValueConst fromMap,JsCommandDomElementOperator & command)216 bool SetDomAttributes(JSContext* ctx, JSValueConst fromMap, JsCommandDomElementOperator& command)
217 {
218     ACE_SCOPED_TRACE("SetDomAttributes");
219 
220     bool hasShowAttr = false;
221     JSPropertyEnum* pTab = nullptr;
222     uint32_t len = 0;
223     if (!CheckAndGetJsProperty(ctx, fromMap, &pTab, &len)) {
224         return hasShowAttr;
225     }
226 
227     std::vector<std::pair<std::string, std::string>> attrs;
228     for (uint32_t i = 0; i < len; i++) {
229         const char* key = JS_AtomToCString(ctx, pTab[i].atom);
230         if (key == nullptr) {
231             JS_FreeAtom(ctx, pTab[i].atom);
232             LOGW("key is null. Ignoring!");
233             continue;
234         }
235         std::string keyString = key;
236         JSValue val = JS_GetProperty(ctx, fromMap, pTab[i].atom);
237         if (JS_IsString(val) || JS_IsNumber(val) || JS_IsBool(val)) {
238             ScopedString styleVal(ctx, val);
239             const char* valStr = styleVal.get();
240             LOGD("SetDomAttributes: key: %{private}s, attr: %{private}s", key, valStr);
241             if (keyString.compare(DOM_ID) == 0) {
242                 command.SetId(valStr);
243             } else if (keyString.compare(DOM_TARGET) == 0) {
244                 command.SetTarget(valStr);
245             } else if (keyString.compare(DOM_SHARE_ID) == 0) {
246                 command.SetShareId(valStr);
247             }
248             attrs.emplace_back(key, valStr);
249             if (keyString.compare(DOM_SHOW) == 0) {
250                 hasShowAttr = true;
251             }
252         } else if (JS_IsArray(ctx, val)) {
253             if (keyString.compare("datasets") == 0) {
254                 auto chartBridge = AceType::MakeRefPtr<ChartBridge>();
255                 chartBridge->GetAttrDatasets(ctx, val);
256                 command.SetDatasets(chartBridge->GetDatasets());
257             } else if (keyString.compare("images") == 0) {
258                 std::vector<ImageProperties> images;
259                 GetAttrImages(ctx, val, images);
260                 command.SetImagesAttr(std::move(images));
261             } else if (keyString.compare("segments") == 0) {
262                 auto chartBridge = AceType::MakeRefPtr<ChartBridge>();
263                 chartBridge->ParseAttrSegmentArray(ctx, val);
264                 command.SetSegments(chartBridge->GetSegments());
265             } else {
266                 std::string valStr;
267                 GetArrayValue(ctx, val, valStr);
268                 LOGD("SetDomAttributes: key: %{private}s, attr: %{private}s", key, valStr.c_str());
269                 attrs.emplace_back(key, valStr);
270             }
271         } else if (JS_IsObject(val)) {
272             if (keyString.compare("options") == 0) {
273                 auto chartBridge = AceType::MakeRefPtr<ChartBridge>();
274                 chartBridge->GetAttrOptionsObject(ctx, val);
275                 command.SetOptions(chartBridge->GetChartOptions());
276             } else if (keyString.compare("segments") == 0) {
277                 auto chartBridge = AceType::MakeRefPtr<ChartBridge>();
278                 chartBridge->ParseAttrSingleSegment(ctx, val);
279                 command.SetSegments(chartBridge->GetSegments());
280             } else if (keyString.compare(DOM_CLOCK_CONFIG) == 0) {
281                 auto clockBridge = AceType::MakeRefPtr<ClockBridge>();
282                 clockBridge->ParseClockConfig(ctx, val);
283                 command.SetClockConfig(clockBridge->GetClockConfig());
284             } else if (keyString.compare(DOM_NODE_TAG_LABEL) == 0) {
285                 auto stepperBridge = AceType::MakeRefPtr<StepperBridge>();
286                 StepperLabels label;
287                 stepperBridge->GetAttrLabel(ctx, val, label);
288                 command.SetStepperLabel(label);
289             } else if (keyString.compare(DOM_BADGE_CONFIG) == 0) {
290                 auto badgeBridge = AceType::MakeRefPtr<BadgeBridge>();
291                 badgeBridge->ParseBadgeConfig(ctx, val);
292                 command.SetBadgeConfig(badgeBridge->GetBadgeConfig());
293             } else {
294                 LOGD("key %{public}s unsupported. Ignoring!", key);
295             }
296         } else if (JS_IsUndefined(val)) {
297             LOGE("value of key[%{private}s] is undefined. Ignoring!", key);
298         } else {
299             LOGE("value of key[%{private}s] of unsupported type. Ignoring!", key);
300         }
301         JS_FreeAtom(ctx, pTab[i].atom);
302         JS_FreeCString(ctx, key);
303         JS_FreeValue(ctx, val);
304     }
305 
306     command.SetAttributes(std::move(attrs));
307     js_free(ctx, pTab);
308     return hasShowAttr;
309 }
310 
GetAndRegisterFamily(JSContext * ctx,JSValueConst valArray,std::string & familyStyle)311 void GetAndRegisterFamily(JSContext* ctx, JSValueConst valArray, std::string& familyStyle)
312 {
313     JSPropertyEnum* tab = nullptr;
314     uint32_t aLen = 0;
315     JS_GetOwnPropertyNames(ctx, &tab, &aLen, valArray, JS_GPN_STRING_MASK);
316 
317     std::string familyVal;
318     std::string srcVal;
319     for (uint32_t j = 0; j < aLen; j++) {
320         // ValObject is one row of family object
321         JSValue valObject = JS_GetProperty(ctx, valArray, tab[j].atom);
322         const char* keyObject = JS_AtomToCString(ctx, tab[j].atom);
323         if (JS_IsString(valObject)) {
324             ScopedString styleVal(ctx, valObject);
325             const char* valStr = styleVal.get();
326             auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
327             ACE_DCHECK(instance);
328             if (keyObject != nullptr && strcmp(keyObject, "fontFamily") == 0) {
329                 familyVal = valStr;
330                 if (!srcVal.empty()) {
331                     instance->GetDelegate()->RegisterFont(familyVal, srcVal);
332                     familyVal.erase();
333                     srcVal.erase();
334                 }
335                 if (familyStyle.length() > 0) {
336                     familyStyle.append(",");
337                 }
338                 familyStyle.append(valStr);
339             } else if (keyObject != nullptr && strcmp(keyObject, "src") == 0) {
340                 srcVal = valStr;
341                 // The format of font src is: url("src"), here get the src.
342                 srcVal = srcVal.substr(5, srcVal.length() - 7);
343                 if (!familyVal.empty()) {
344                     instance->GetDelegate()->RegisterFont(familyVal, srcVal);
345                     familyVal.erase();
346                     srcVal.erase();
347                 }
348             }
349         }
350         JS_FreeAtom(ctx, tab[j].atom);
351         JS_FreeCString(ctx, keyObject);
352         JS_FreeValue(ctx, valObject);
353     }
354     js_free(ctx, tab);
355 }
356 
GetStyleFamilyValue(JSContext * ctx,JSValueConst arrayVal,std::string & familyStyle)357 void GetStyleFamilyValue(JSContext* ctx, JSValueConst arrayVal, std::string& familyStyle)
358 {
359     int32_t length = QJSUtils::JsGetArrayLength(ctx, arrayVal);
360     for (int32_t i = 0; i < length; ++i) {
361         // ValArray is one row of family array
362         JSValue valArray = JS_GetPropertyUint32(ctx, arrayVal, i);
363         if (JS_IsObject(valArray)) {
364             GetAndRegisterFamily(ctx, valArray, familyStyle);
365         }
366         JS_FreeValue(ctx, valArray);
367     }
368 }
369 
GetStyleAnimationName(JSContext * ctx,JSValueConst arrayVal,std::vector<std::unordered_map<std::string,std::string>> & styleVec)370 void GetStyleAnimationName(
371     JSContext* ctx, JSValueConst arrayVal, std::vector<std::unordered_map<std::string, std::string>>& styleVec)
372 {
373     int32_t length = QJSUtils::JsGetArrayLength(ctx, arrayVal);
374     for (int32_t i = 0; i < length; ++i) {
375         std::unordered_map<std::string, std::string> animationNameKeyFrame;
376         JSValue valArray = JS_GetPropertyUint32(ctx, arrayVal, i);
377         if (JS_IsObject(valArray)) {
378             JSPropertyEnum* tab = nullptr;
379             uint32_t anotherLen = 0;
380             JS_GetOwnPropertyNames(ctx, &tab, &anotherLen, valArray, JS_GPN_STRING_MASK);
381             for (uint32_t j = 0; j < anotherLen; ++j) {
382                 const char* key = JS_AtomToCString(ctx, tab[j].atom);
383                 if (key == nullptr) {
384                     JS_FreeAtom(ctx, tab[j].atom);
385                     JS_FreeValue(ctx, valArray);
386                     LOGW("key is null. Ignoring!");
387                     continue;
388                 }
389                 JSValue valObject = JS_GetProperty(ctx, valArray, tab[j].atom);
390                 if (JS_IsString(valObject) || JS_IsNumber(valObject)) {
391                     ScopedString styleVal(ctx, valObject);
392                     const char* valStr = styleVal.get();
393                     animationNameKeyFrame.emplace(key, valStr);
394                 } else {
395                     LOGD("GetStyleAnimationName: unsupported type :%{public}d", JS_VALUE_GET_TAG(valObject));
396                 }
397                 JS_FreeAtom(ctx, tab[j].atom);
398                 JS_FreeCString(ctx, key);
399                 JS_FreeValue(ctx, valObject);
400             }
401             js_free(ctx, tab);
402         }
403         if (animationNameKeyFrame.size() > 0) {
404             styleVec.emplace_back(animationNameKeyFrame);
405         }
406         JS_FreeValue(ctx, valArray);
407     }
408 }
409 
SetDomStyle(JSContext * ctx,JSValueConst fromMap,JsCommandDomElementOperator & command)410 void SetDomStyle(JSContext* ctx, JSValueConst fromMap, JsCommandDomElementOperator& command)
411 {
412     ACE_SCOPED_TRACE("SetDomStyle");
413 
414     JSPropertyEnum* pTab = nullptr;
415     uint32_t len = 0;
416     if (!CheckAndGetJsProperty(ctx, fromMap, &pTab, &len)) {
417         return;
418     }
419 
420     std::vector<std::pair<std::string, std::string>> styles;
421     for (uint32_t i = 0; i < len; i++) {
422         const char* key = JS_AtomToCString(ctx, pTab[i].atom);
423         if (key == nullptr) {
424             JS_FreeAtom(ctx, pTab[i].atom);
425             LOGW("key is null. Ignoring!");
426             continue;
427         }
428         std::string keyString = key;
429         JSValue val = JS_GetProperty(ctx, fromMap, pTab[i].atom);
430         if (JS_IsString(val) || JS_IsNumber(val) || JS_IsBool(val)) {
431             ScopedString styleVal(ctx, val);
432             const char* valStr = styleVal.get();
433             LOGD("SetDomStyle: key: %{private}s, style: %{private}s", key, valStr);
434             styles.emplace_back(key, valStr);
435         } else if (JS_IsArray(ctx, val)) {
436             if (keyString.compare(DOM_TEXT_FONT_FAMILY) == 0) {
437                 // Deal with special case such as fontFamily, suppose all the keys in the array are the same.
438                 std::string familyStyle;
439                 GetStyleFamilyValue(ctx, val, familyStyle);
440                 styles.emplace_back(key, familyStyle);
441             } else if (keyString.compare(DOM_ANIMATION_NAME) == 0) {
442                 // Deal with special case animationName, it different with fontfamily,
443                 // the keys in the array are different.
444                 std::vector<std::unordered_map<std::string, std::string>> animationStyles;
445                 GetStyleAnimationName(ctx, val, animationStyles);
446                 command.SetAnimationStyles(std::move(animationStyles));
447             } else if (keyString.compare(DOM_TRANSITION_ENTER) == 0) {
448                 std::vector<std::unordered_map<std::string, std::string>> transitionEnter;
449                 GetStyleAnimationName(ctx, val, transitionEnter);
450                 command.SetTransitionEnter(std::move(transitionEnter));
451             } else if (keyString.compare(DOM_TRANSITION_EXIT) == 0) {
452                 std::vector<std::unordered_map<std::string, std::string>> transitionExit;
453                 GetStyleAnimationName(ctx, val, transitionExit);
454                 command.SetTransitionExit(std::move(transitionExit));
455             } else if (keyString.compare(DOM_SHARED_TRANSITION_NAME) == 0) {
456                 std::vector<std::unordered_map<std::string, std::string>> sharedTransitionName;
457                 GetStyleAnimationName(ctx, val, sharedTransitionName);
458                 command.SetSharedTransitionName(std::move(sharedTransitionName));
459             } else {
460                 LOGD("value is array, key unsupported. Ignoring!");
461             }
462         } else if (JS_IsUndefined(val)) {
463             LOGD("value is undefined. Ignoring!");
464         } else {
465             LOGD("value of unsupported type. Ignoring!");
466         }
467         JS_FreeAtom(ctx, pTab[i].atom);
468         JS_FreeCString(ctx, key);
469         JS_FreeValue(ctx, val);
470     }
471     bool isIine = false;
472     for (int32_t i = 0; i < static_cast<int32_t>(styles.size()); i++) {
473         std::string key = styles[i].first;
474         std::string value = styles[i].second;
475         if (key == "display" && value == "inline") {
476             isIine = true;
477             break;
478         }
479     }
480 
481     if (isIine) {
482         std::vector<std::pair<std::string, std::string>> stylesFinally;
483         for (int32_t i = 0; i < static_cast<int32_t>(styles.size()); i++) {
484             std::string key = styles[i].first;
485             std::string value = styles[i].second;
486             if (key == "width" || key == "height" || key.find("margin") != std::string::npos ||
487                 key.find("padding") != std::string::npos) {
488                 continue;
489             } else {
490                 stylesFinally.emplace_back(key, value);
491             }
492         }
493         command.SetStyles(std::move(stylesFinally));
494     } else {
495         command.SetStyles(std::move(styles));
496     }
497 
498     QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
499     auto pipelineContext = AceType::DynamicCast<PipelineContext>(instance->GetDelegate()->GetPipelineContext());
500     command.SetPipelineContext(pipelineContext);
501     js_free(ctx, pTab);
502 }
503 
AddDomEvent(JSContext * ctx,JSValueConst fromArray,JsCommandDomElementOperator & command)504 void AddDomEvent(JSContext* ctx, JSValueConst fromArray, JsCommandDomElementOperator& command)
505 {
506     ACE_SCOPED_TRACE("AddDomEvent");
507 
508     std::vector<std::string> eventsMap;
509     int32_t length = QJSUtils::JsGetArrayLength(ctx, fromArray);
510     for (int32_t i = 0; i < length; i++) {
511         JSValue val = JS_GetPropertyUint32(ctx, fromArray, i);
512         if (JS_IsString(val)) {
513             ScopedString styleVal(ctx, val);
514             const char* valStr = styleVal.get();
515             eventsMap.emplace_back(valStr);
516         } else {
517             LOGW("value of unsupported type. Ignoring!");
518         }
519         JS_FreeValue(ctx, val);
520     }
521     command.AddEvents(std::move(eventsMap));
522 }
523 
JsRemoveElement(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)524 JSValue JsRemoveElement(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
525 {
526     if ((argv == nullptr) || (argc != REMOVE_ELEMENT_ARGS_LEN)) {
527         LOGE("JsRemoveElement: the arg is error when call removeElement");
528         return JS_EXCEPTION;
529     }
530 
531     auto page = GetRunningPage(ctx);
532     if (page == nullptr) {
533         return JS_EXCEPTION;
534     }
535 
536     int32_t instanceId = 0;
537     JS_ToInt32(ctx, &instanceId, argv[REMOVE_ELEMENT_INSTANCE_ID]);
538     if (page->GetPageId() != instanceId) {
539         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
540         ACE_DCHECK(instance);
541         page = instance->GetDelegate()->GetPage(instanceId);
542         if (page == nullptr) {
543             LOGE("JsRemoveElement fail to get page, pageId: %{public}d", instanceId);
544             return JS_EXCEPTION;
545         }
546     }
547 
548     int32_t nodeId = 0;
549     JS_ToInt32(ctx, &nodeId, argv[0]);
550     nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
551     page->PushCommand(Referenced::MakeRefPtr<JsCommandRemoveDomElement>(nodeId));
552     return JS_NULL;
553 }
554 
JsUpdateElementAttrs(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)555 JSValue JsUpdateElementAttrs(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
556 {
557     if ((argv == nullptr) || (argc != UPLOAD_ELEMENT_ARGS_LEN)) {
558         LOGE("the arg is error");
559         return JS_EXCEPTION;
560     }
561 
562     auto page = GetStagingPage(ctx);
563     if (page == nullptr) {
564         return JS_EXCEPTION;
565     }
566 
567     int32_t instanceId = 0;
568     JS_ToInt32(ctx, &instanceId, argv[UPLOAD_ELEMENT_INSTANCE_ID]);
569     if (page->GetPageId() != instanceId) {
570         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
571         ACE_DCHECK(instance);
572         page = instance->GetDelegate()->GetPage(instanceId);
573         if (page == nullptr) {
574             LOGE("JsUpdateElementAttrs fail to get page, pageId :%{public}d", instanceId);
575             return JS_EXCEPTION;
576         }
577     }
578 
579     int32_t nodeId = 0;
580     JS_ToInt32(ctx, &nodeId, argv[0]);
581     nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
582     auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementAttrs>(nodeId);
583     if (SetDomAttributes(ctx, argv[1], *command)) {
584         page->ReserveShowCommand(command);
585     }
586     page->PushCommand(command);
587     return JS_NULL;
588 }
589 
JsUpdateElementStyles(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)590 JSValue JsUpdateElementStyles(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
591 {
592     if ((argv == nullptr) || (argc != UPLOAD_ELEMENT_ARGS_LEN)) {
593         LOGE("the arg is error");
594         return JS_EXCEPTION;
595     }
596 
597     auto page = GetStagingPage(ctx);
598     if (page == nullptr) {
599         return JS_EXCEPTION;
600     }
601 
602     int32_t instanceId = 0;
603     JS_ToInt32(ctx, &instanceId, argv[UPLOAD_ELEMENT_INSTANCE_ID]);
604     if (page->GetPageId() != instanceId) {
605         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
606         ACE_DCHECK(instance);
607         page = instance->GetDelegate()->GetPage(instanceId);
608         if (page == nullptr) {
609             LOGE("JsUpdateElementStyles fail to get page, pageId: %{public}d", instanceId);
610             return JS_EXCEPTION;
611         }
612     }
613 
614     int32_t nodeId = 0;
615     JS_ToInt32(ctx, &nodeId, argv[0]);
616     nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
617     auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementStyles>(nodeId);
618     SetDomStyle(ctx, argv[1], *command);
619     page->PushCommand(command);
620     return JS_NULL;
621 }
622 
JsDomCreateBody(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)623 JSValue JsDomCreateBody(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
624 {
625     if ((argv == nullptr) || (argc != 5)) {
626         LOGE("the arg is error");
627         return JS_EXCEPTION;
628     }
629 
630     auto page = GetStagingPage(ctx);
631     if (page == nullptr) {
632         return JS_EXCEPTION;
633     }
634 
635     int32_t nodeId = DOM_ROOT_NODE_ID_BASE + page->GetPageId();
636     LOGD("JsDomCreateBody: pageId: %{private}d, nodeId: %{private}d:", page->GetPageId(), nodeId);
637 
638     ScopedString tag(ctx, argv[1]);
639     auto command = Referenced::MakeRefPtr<JsCommandCreateDomBody>(tag.get(), nodeId);
640 
641     SetDomAttributes(ctx, argv[2], *command);
642     SetDomStyle(ctx, argv[3], *command);
643     AddDomEvent(ctx, argv[4], *command);
644     page->PushCommand(command);
645     return JS_NULL;
646 }
647 
CreateDomElement(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)648 int32_t CreateDomElement(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
649 {
650     ACE_SCOPED_TRACE("CreateDomElement");
651     if (argv == nullptr) {
652         LOGE("the arg is error");
653         return -1;
654     }
655 
656     auto page = GetStagingPage(ctx);
657     if (page == nullptr) {
658         LOGE("the page is nullptr");
659         return -1;
660     }
661     int32_t nodeId = ++globalNodeId;
662     ScopedString tag(ctx, argv[0]);
663     auto command = Referenced::MakeRefPtr<JsCommandCreateDomElement>(tag.get(), nodeId);
664     page->PushCommand(command);
665     // Flush command as fragment immediately when pushed too many commands.
666     if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
667         page->FlushCommands();
668     }
669     return globalNodeId;
670 }
671 
JsDomAddElement(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)672 JSValue JsDomAddElement(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
673 {
674     ACE_SCOPED_TRACE("JsDomAddElement");
675 
676     if ((argv == nullptr) || (argc != ADD_ELEMENT_ARGS_LEN)) {
677         LOGE("the arg is error");
678         return JS_EXCEPTION;
679     }
680 
681     auto page = GetStagingPage(ctx);
682     if (page == nullptr) {
683         return JS_EXCEPTION;
684     }
685 
686     int32_t instanceId = 0;
687     JS_ToInt32(ctx, &instanceId, argv[ADD_ELEMENT_INSTANCE_ID]);
688     if (page->GetPageId() != instanceId) {
689         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
690         ACE_DCHECK(instance);
691         page = instance->GetDelegate()->GetPage(instanceId);
692         if (page == nullptr) {
693             LOGE("JsDomAddElement fail to get page, pageId: %{public}d", instanceId);
694             return JS_EXCEPTION;
695         }
696     }
697 
698     int32_t parentNodeId;
699     JS_ToInt32(ctx, &parentNodeId, argv[0]);
700     parentNodeId = parentNodeId ? parentNodeId : (DOM_ROOT_NODE_ID_BASE + page->GetPageId());
701 
702     int32_t nodeId;
703     JS_ToInt32(ctx, &nodeId, argv[1]);
704     ScopedString tag(ctx, argv[2]);
705     LOGD("JsDomAddElement: pageId: %{private}d, parentNodeId: %{private}d, nodeId: %{private}d, tag: %{private}s",
706         page->GetPageId(), parentNodeId, nodeId, tag.get());
707     auto command = Referenced::MakeRefPtr<JsCommandAddDomElement>(tag.get(), nodeId, parentNodeId);
708     SetDomAttributes(ctx, argv[3], *command);
709     SetDomStyle(ctx, argv[4], *command);
710     AddDomEvent(ctx, argv[5], *command);
711 
712     ScopedString customFlag(ctx, argv[6]);
713     if (customFlag.get()) {
714         std::unique_ptr<JsonValue> customPtr = JsonUtil::ParseJsonString(customFlag.get());
715         if (customPtr && customPtr->IsBool()) {
716             command->SetIsCustomComponent(customPtr->GetBool());
717         }
718     }
719     int32_t itemIndex;
720     JS_ToInt32(ctx, &itemIndex, argv[7]);
721     command->SetForIndex(itemIndex);
722     page->PushCommand(command);
723     // Flush command as fragment immediately when pushed too many commands.
724     if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
725         page->FlushCommands();
726     }
727     return JS_NULL;
728 }
729 
730 // JS Framework calls this function after initial loading of the page has been done.
JsOnCreateFinish(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)731 JSValue JsOnCreateFinish(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
732 {
733     LOGD("JsOnCreateFinish");
734     auto page = GetStagingPage(ctx);
735     if (page == nullptr) {
736         return JS_EXCEPTION;
737     }
738     page->SetPageCreated();
739     return JS_NULL;
740 }
741 
742 // JS Framework calls this function after JS framework has finished processing an event.
JsOnUpdateFinish(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)743 JSValue JsOnUpdateFinish(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
744 {
745     LOGD("JsOnUpdateFinish");
746     auto page = GetRunningPage(ctx);
747     if (page == nullptr) {
748         return JS_EXCEPTION;
749     }
750 
751     if (page->CheckPageCreated()) {
752         QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
753         ACE_DCHECK(instance);
754         instance->GetDelegate()->TriggerPageUpdate(page->GetPageId());
755     }
756     return JS_NULL;
757 }
758 
JsParseRouteUrl(JSContext * ctx,JSValueConst argv,const std::string & key)759 std::string JsParseRouteUrl(JSContext* ctx, JSValueConst argv, const std::string& key)
760 {
761     std::string pageRoute;
762     ScopedString args(ctx, argv);
763     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
764     if (argsPtr != nullptr && argsPtr->GetValue(key) != nullptr && argsPtr->GetValue(key)->IsString()) {
765         pageRoute = argsPtr->GetValue(key)->GetString();
766     }
767     LOGI("JsParseRouteUrl pageRoute = %{private}s", pageRoute.c_str());
768     return pageRoute;
769 }
770 
JsParseRouteUrlSpecial(JSContext * ctx,JSValueConst argv)771 std::string JsParseRouteUrlSpecial(JSContext* ctx, JSValueConst argv)
772 {
773     std::string pageRoute;
774     ScopedString args(ctx, argv);
775     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
776 
777     if (argsPtr->Contains(ROUTE_KEY_URI)) {
778         pageRoute = argsPtr->GetValue(ROUTE_KEY_URI)->GetString();
779     } else if (argsPtr->Contains(ROUTE_KEY_PATH)) {
780         pageRoute = argsPtr->GetValue(ROUTE_KEY_PATH)->GetString();
781     }
782     LOGI("JsParseRouteUrl pageRoute = %{private}s", pageRoute.c_str());
783     return pageRoute;
784 }
785 
JsParseRouteParams(JSContext * ctx,JSValueConst argv,const std::string & key)786 std::string JsParseRouteParams(JSContext* ctx, JSValueConst argv, const std::string& key)
787 {
788     std::string params;
789     ScopedString args(ctx, argv);
790 
791     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
792     if (argsPtr != nullptr && argsPtr->Contains(key) && argsPtr->GetValue(key)->IsObject()) {
793         params = argsPtr->GetValue(key)->ToString();
794     }
795     return params;
796 }
797 
JsParseIntParams(JSContext * ctx,JSValueConst argv,const std::string & key)798 int32_t JsParseIntParams(JSContext* ctx, JSValueConst argv, const std::string& key)
799 {
800     ScopedString args(ctx, argv);
801 
802     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
803     if (argsPtr != nullptr && argsPtr->Contains(key) && argsPtr->GetValue(key)->IsNumber()) {
804         return argsPtr->GetValue(key)->GetInt();
805     }
806 
807     return 0;
808 }
809 
JsParseRouteOverwrite(JSContext * ctx,JSValueConst argv,const std::string & key)810 bool JsParseRouteOverwrite(JSContext* ctx, JSValueConst argv, const std::string& key)
811 {
812     ScopedString args(ctx, argv);
813 
814     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
815     if (argsPtr != nullptr && argsPtr->Contains(key)) {
816         return true;
817     }
818     return false;
819 }
820 
JsParseDialogButtons(JSContext * ctx,JSValueConst argv,const std::string & key)821 std::vector<ButtonInfo> JsParseDialogButtons(JSContext* ctx, JSValueConst argv, const std::string& key)
822 {
823     std::vector<ButtonInfo> dialogButtons;
824     ScopedString args(ctx, argv);
825     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
826     if (argsPtr != nullptr && argsPtr->GetValue(key) != nullptr && argsPtr->GetValue(key)->IsArray()) {
827         for (int32_t i = 0; i < argsPtr->GetValue(key)->GetArraySize(); ++i) {
828             auto button = argsPtr->GetValue(key)->GetArrayItem(i);
829             if (!button || !button->GetValue("text")->IsString()) {
830                 continue;
831             }
832             ButtonInfo buttonInfo;
833             if (button->GetValue("text")) {
834                 buttonInfo.text = button->GetValue("text")->GetString();
835             }
836             if (button->GetValue("color")) {
837                 buttonInfo.textColor = button->GetValue("color")->GetString();
838             }
839             dialogButtons.emplace_back(buttonInfo);
840         }
841     }
842     return dialogButtons;
843 }
844 
EnableAlertBeforeBackPage(JSContext * ctx,JSValueConst argv)845 JSValue EnableAlertBeforeBackPage(JSContext* ctx, JSValueConst argv)
846 {
847     ScopedString args(ctx, argv);
848     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
849 
850     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
851     if (argsPtr != nullptr && argsPtr->IsObject()) {
852         if (argsPtr->GetValue(PROMPT_KEY_MESSAGE) == nullptr || !argsPtr->GetValue(PROMPT_KEY_MESSAGE)->IsString()) {
853             LOGE("enableAlertBeforeBackPage message is null");
854             const std::string fail = JsParseRouteUrl(ctx, argv, COMMON_FAIL);
855             const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
856             instance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:massage is null"})", false);
857             instance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:massage is null"})", false);
858             return JS_NULL;
859         }
860     } else {
861         LOGE("enableAlertBeforeBackPage message is null");
862         std::string callBackStr(args.get());
863         // Get callbackId and clear redundant symbols
864         if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
865             callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
866             instance->CallJs(callBackStr,
867                 R"({"arguments":[{"errMsg":"enableAlertBeforeBackPage:massage is null"}],"method":"fail"})", false);
868         }
869         return JS_NULL;
870     }
871 
872     const std::string message = JsParseRouteUrl(ctx, argv, PROMPT_KEY_MESSAGE);
873     const std::string success = JsParseRouteUrl(ctx, argv, COMMON_SUCCESS);
874     const std::string fail = JsParseRouteUrl(ctx, argv, COMMON_FAIL);
875     const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
876     auto callback = [instance, success, fail, complete](int32_t callbackType) {
877         switch (callbackType) {
878             case 0:
879                 instance->CallJs(success, R"({"errMsg":"enableAlertBeforeBackPage:ok"})", false);
880                 instance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:ok"})", false);
881                 break;
882             case 1:
883                 instance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:fail cancel"})", false);
884                 instance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:fail cancel"})", false);
885                 break;
886             default:
887                 break;
888         }
889     };
890     instance->GetDelegate()->EnableAlertBeforeBackPage(message, std::move(callback));
891     return JS_NULL;
892 }
893 
DisableAlertBeforeBackPage(JSContext * ctx,JSValueConst argv)894 JSValue DisableAlertBeforeBackPage(JSContext* ctx, JSValueConst argv)
895 {
896     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
897     instance->GetDelegate()->DisableAlertBeforeBackPage();
898 
899     ScopedString args(ctx, argv);
900     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
901     if (argsPtr->IsObject()) {
902         const std::string success = JsParseRouteUrl(ctx, argv, COMMON_SUCCESS);
903         const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
904         instance->CallJs(success, R"({"errMsg":"disableAlertBeforeBackPage:ok"})", false);
905         instance->CallJs(complete, R"({"errMsg":"disableAlertBeforeBackPage:ok"})", false);
906         return JS_NULL;
907     }
908 
909     std::string callBackStr(args.get());
910     // Get callbackId and clear redundant symbols
911     if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
912         callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
913         instance->CallJs(
914             callBackStr, R"({"arguments":[{"errMsg":"disableAlertBeforeBackPage:ok"}],"method":"success"})", false);
915     }
916     return JS_NULL;
917 }
918 
PostponePageTransition(JSContext * ctx,JSValueConst argv)919 JSValue PostponePageTransition(JSContext* ctx, JSValueConst argv)
920 {
921     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
922     instance->GetDelegate()->PostponePageTransition();
923     return JS_NULL;
924 }
925 
LaunchPageTransition(JSContext * ctx,JSValueConst argv)926 JSValue LaunchPageTransition(JSContext* ctx, JSValueConst argv)
927 {
928     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
929     instance->GetDelegate()->LaunchPageTransition();
930     return JS_NULL;
931 }
932 
JsHandlePageRoute(JSContext * ctx,JSValueConst argv,const std::string & methodName)933 JSValue JsHandlePageRoute(JSContext* ctx, JSValueConst argv, const std::string& methodName)
934 {
935     std::string uri = "";
936     if (methodName == ROUTE_PAGE_BACK) {
937         uri = JsParseRouteUrlSpecial(ctx, argv);
938     } else {
939         uri = JsParseRouteUrl(ctx, argv, ROUTE_KEY_URI);
940     }
941     std::string params = JsParseRouteParams(ctx, argv, ROUTE_KEY_PARAMS);
942     bool dontOverwrite = JsParseRouteOverwrite(ctx, argv, ROUTE_KEY_DONT_OVERWRITE);
943 
944     std::unique_ptr<JsonValue> routerParamsData = JsonUtil::Create(true);
945     routerParamsData->Put("paramsData", JsonUtil::ParseJsonString(params));
946     routerParamsData->Put("dontOverwrite", dontOverwrite);
947     params = routerParamsData->ToString();
948 
949     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
950     // Operator map for page route.
951     static const LinearMapNode<JSValue (*)(const std::string&, const std::string&, QjsEngineInstance&)>
952         pageRouteOperators[] = {
953             { ROUTE_PAGE_BACK,
954                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
955                     LOGD("JsBackRoute uri = %{private}s", uri.c_str());
956                     instance.GetDelegate()->Back(uri, params);
957                     return JS_NULL;
958                 } },
959             { ROUTE_PAGE_CLEAR,
960                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
961                     LOGD("Clear Page Route");
962                     instance.GetDelegate()->Clear();
963                     return JS_NULL;
964                 } },
965             { ROUTE_PAGE_GET_LENGTH,
966                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
967                     int32_t routeLength = instance.GetDelegate()->GetStackSize();
968                     std::string indexLength = std::to_string(routeLength);
969                     LOGD("JsGetLengthRoute routeLength=%{private}s", indexLength.c_str());
970                     auto ctx = instance.GetQjsContext();
971                     return JS_NewString(ctx, indexLength.c_str());
972                 } },
973             { ROUTE_PAGE_GET_STATE,
974                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
975                     int32_t routeIndex = 0;
976                     std::string routeName;
977                     std::string routePath;
978                     instance.GetDelegate()->GetState(routeIndex, routeName, routePath);
979                     LOGD("JsGetStateRoute index=%{private}d name=%{private}s path=%{private}s", routeIndex,
980                         routeName.c_str(), routePath.c_str());
981 
982                     auto ctx = instance.GetQjsContext();
983                     JSValue routeData = JS_NewObject(ctx);
984                     JS_SetPropertyStr(ctx, routeData, "index", JS_NewInt32(ctx, routeIndex));
985                     JS_SetPropertyStr(ctx, routeData, "name", JS_NewString(ctx, routeName.c_str()));
986                     JS_SetPropertyStr(ctx, routeData, "path", JS_NewString(ctx, routePath.c_str()));
987                     return routeData;
988                 } },
989             { ROUTE_PAGE_PUSH,
990                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
991                     LOGD("JsPushRoute uri = %{private}s", uri.c_str());
992                     instance.GetDelegate()->Push(uri, params);
993                     return JS_NULL;
994                 } },
995             { ROUTE_PAGE_REPLACE,
996                 [](const std::string& uri, const std::string& params, QjsEngineInstance& instance) {
997                     LOGD("JsReplaceRoute uri = %{private}s", uri.c_str());
998                     instance.GetDelegate()->Replace(uri, params);
999                     return JS_NULL;
1000                 } },
1001         };
1002     auto operatorIter = BinarySearchFindIndex(pageRouteOperators, ArraySize(pageRouteOperators), methodName.c_str());
1003     if (operatorIter != -1) {
1004         return pageRouteOperators[operatorIter].value(uri, params, *instance);
1005     } else if (methodName == ROUTE_ENABLE_ALERT_BEFORE_BACK_PAGE) {
1006         return EnableAlertBeforeBackPage(ctx, argv);
1007     } else if (methodName == ROUTE_DISABLE_ALERT_BEFORE_BACK_PAGE) {
1008         return DisableAlertBeforeBackPage(ctx, argv);
1009     } else if (methodName == ROUTE_POSTPONE) {
1010         return PostponePageTransition(ctx, argv);
1011     } else if (methodName == ROUTE_LAUNCH) {
1012         return LaunchPageTransition(ctx, argv);
1013     } else {
1014         LOGW("system.router not support method = %{private}s", methodName.c_str());
1015     }
1016     return JS_NULL;
1017 }
1018 
JsShowToast(JSContext * ctx,JSValueConst argv)1019 JSValue JsShowToast(JSContext* ctx, JSValueConst argv)
1020 {
1021     ScopedString args(ctx, argv);
1022     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
1023     std::string message;
1024     int32_t duration = 0;
1025     std::string bottom;
1026     if (argsPtr != nullptr) {
1027         if (argsPtr->GetValue(PROMPT_KEY_MESSAGE) != nullptr) {
1028             if (argsPtr->GetValue(PROMPT_KEY_MESSAGE)->IsString()) {
1029                 message = argsPtr->GetValue(PROMPT_KEY_MESSAGE)->GetString();
1030             } else {
1031                 message = argsPtr->GetValue(PROMPT_KEY_MESSAGE)->ToString();
1032             }
1033         }
1034         if (argsPtr->GetValue(PROMPT_KEY_DURATION) != nullptr && argsPtr->GetValue(PROMPT_KEY_DURATION)->IsNumber()) {
1035             duration = argsPtr->GetValue(PROMPT_KEY_DURATION)->GetInt();
1036         }
1037         if (argsPtr->GetValue(PROMPT_KEY_BOTTOM) != nullptr) {
1038             if (argsPtr->GetValue(PROMPT_KEY_BOTTOM)->IsString()) {
1039                 bottom = argsPtr->GetValue(PROMPT_KEY_BOTTOM)->GetString();
1040             } else if (argsPtr->GetValue(PROMPT_KEY_BOTTOM)->IsNumber()) {
1041                 bottom = std::to_string(argsPtr->GetValue(PROMPT_KEY_BOTTOM)->GetInt());
1042             }
1043         }
1044     }
1045     LOGD("JsShowToast message = %{private}s duration = %{private}d bottom = %{private}s", message.c_str(), duration,
1046         bottom.c_str());
1047     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1048     ACE_DCHECK(instance);
1049     instance->GetDelegate()->ShowToast(message, duration, bottom);
1050     return JS_NULL;
1051 }
1052 
JsShowDialog(JSContext * ctx,JSValueConst argv)1053 JSValue JsShowDialog(JSContext* ctx, JSValueConst argv)
1054 {
1055     const std::string title = JsParseRouteUrl(ctx, argv, PROMPT_KEY_TITLE);
1056     const std::string message = JsParseRouteUrl(ctx, argv, PROMPT_KEY_MESSAGE);
1057     std::vector<ButtonInfo> buttons = JsParseDialogButtons(ctx, argv, PROMPT_KEY_BUTTONS);
1058     const std::string success = JsParseRouteUrl(ctx, argv, COMMON_SUCCESS);
1059     const std::string cancel = JsParseRouteUrl(ctx, argv, COMMON_CANCEL);
1060     const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
1061     bool autoCancel = true;
1062 
1063     ScopedString args(ctx, argv);
1064     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
1065     if (argsPtr != nullptr && argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL) != nullptr &&
1066         argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL)->IsBool()) {
1067         autoCancel = argsPtr->GetValue(PROMPT_DIALOG_AUTO_CANCEL)->GetBool();
1068     }
1069 
1070     std::set<std::string> callbacks;
1071     if (!success.empty()) {
1072         callbacks.emplace(COMMON_SUCCESS);
1073     }
1074     if (!cancel.empty()) {
1075         callbacks.emplace(COMMON_CANCEL);
1076     }
1077     if (!complete.empty()) {
1078         callbacks.emplace(COMMON_COMPLETE);
1079     }
1080 
1081     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1082     auto callback = [instance, success, cancel, complete](int32_t callbackType, int32_t successType) {
1083         switch (callbackType) {
1084             case 0:
1085                 instance->CallJs(success.c_str(),
1086                     std::string("{\"index\":").append(std::to_string(successType)).append("}").c_str(), false);
1087                 break;
1088             case 1:
1089                 instance->CallJs(cancel.c_str(), std::string("\"cancel\",null").c_str(), false);
1090                 break;
1091             case 2:
1092                 instance->CallJs(complete.c_str(), std::string("\"complete\",null").c_str(), false);
1093                 break;
1094             default:
1095                 break;
1096         }
1097     };
1098     instance->GetDelegate()->ShowDialog(title, message, buttons, autoCancel, std::move(callback), callbacks);
1099     return JS_NULL;
1100 }
1101 
JsShowActionMenu(JSContext * ctx,JSValueConst argv)1102 JSValue JsShowActionMenu(JSContext* ctx, JSValueConst argv)
1103 {
1104     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1105 
1106     ScopedString args(ctx, argv);
1107     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
1108     if (argsPtr == nullptr) {
1109         LOGE("argsPtr is nullptr");
1110         return JS_NULL;
1111     }
1112 
1113     std::vector<ButtonInfo> buttons = JsParseDialogButtons(ctx, argv, PROMPT_KEY_BUTTONS);
1114     // The number of buttons cannot be zero or more than six
1115     if (buttons.empty() || buttons.size() > 6) {
1116         LOGE("buttons is invalid");
1117         if (argsPtr->IsObject()) {
1118             const std::string fail = JsParseRouteUrl(ctx, argv, COMMON_FAIL);
1119             const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
1120             instance->CallJs(fail, R"({"errMsg":"enableAlertBeforeBackPage:buttons is invalid"})", false);
1121             instance->CallJs(complete, R"({"errMsg":"enableAlertBeforeBackPage:buttons is invalid"})", false);
1122         } else {
1123             std::string callBackStr(args.get());
1124             // Get callbackId and clear redundant symbols
1125             if (callBackStr.size() > 2 && callBackStr.front() == '\"' && callBackStr.back() == '\"') {
1126                 callBackStr = callBackStr.substr(1, callBackStr.size() - 2);
1127                 instance->CallJs(callBackStr,
1128                     R"({"arguments":[{"errMsg":"enableAlertBeforeBackPage:buttons is invalid"}],"method":"fail"})",
1129                     false);
1130             }
1131         }
1132         return JS_NULL;
1133     }
1134 
1135     const std::string title = JsParseRouteUrl(ctx, argv, PROMPT_KEY_TITLE);
1136     const std::string success = JsParseRouteUrl(ctx, argv, COMMON_SUCCESS);
1137     const std::string fail = JsParseRouteUrl(ctx, argv, COMMON_FAIL);
1138     const std::string complete = JsParseRouteUrl(ctx, argv, COMMON_COMPLETE);
1139     auto callback = [instance, success, fail, complete](int32_t callbackType, int32_t successType) {
1140         switch (callbackType) {
1141             case 0:
1142                 instance->CallJs(success.c_str(), std::string(R"({"errMsg":"showActionMenu:ok","tapIndex":)")
1143                     .append(std::to_string(successType)).append("}").c_str(), false);
1144                 instance->CallJs(complete.c_str(), std::string(R"({"errMsg":"showActionMenu:ok","tapIndex":)")
1145                     .append(std::to_string(successType)).append("}").c_str(), false);
1146                 break;
1147             case 1:
1148                 instance->CallJs(fail, R"({"errMsg":"showActionMenu:fail cancel"})", false);
1149                 instance->CallJs(complete, R"({"errMsg":"showActionMenu:fail cancel"})", false);
1150                 break;
1151             default:
1152                 LOGE("callbackType is invalid");
1153                 break;
1154         }
1155     };
1156     instance->GetDelegate()->ShowActionMenu(title, buttons, std::move(callback));
1157     return JS_NULL;
1158 }
1159 
JsHandlePrompt(JSContext * ctx,JSValueConst argv,const std::string & methodName)1160 JSValue JsHandlePrompt(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1161 {
1162     if (methodName == PROMPT_SHOW_TOAST) {
1163         return JsShowToast(ctx, argv);
1164     } else if (methodName == PROMPT_SHOW_DIALOG) {
1165         return JsShowDialog(ctx, argv);
1166     } else if (methodName == PROMPT_SHOW_ACTION_MENU) {
1167         return JsShowActionMenu(ctx, argv);
1168     } else {
1169         LOGW("system.prompt not support method = %{private}s", methodName.c_str());
1170     }
1171     return JS_NULL;
1172 }
1173 
JsHandleAnimationFrame(JSContext * ctx,JSValueConst argv,const std::string & methodName)1174 JSValue JsHandleAnimationFrame(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1175 {
1176     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1177     if (instance == nullptr) {
1178         return JS_NULL;
1179     }
1180     const char* callbackIdJsStr = JS_ToCString(ctx, argv);
1181     if (callbackIdJsStr == nullptr) {
1182         LOGW("system animation callbackId is null");
1183         return JS_NULL;
1184     }
1185     if (methodName == ANIMATION_REQUEST_ANIMATION_FRAME) {
1186         instance->GetDelegate()->RequestAnimationFrame(std::string(callbackIdJsStr));
1187     } else if (methodName == ANIMATION_CANCEL_ANIMATION_FRAME) {
1188         instance->GetDelegate()->CancelAnimationFrame(std::string(callbackIdJsStr));
1189     } else {
1190         LOGW("animationFrame not support method = %{private}s", methodName.c_str());
1191     }
1192     JS_FreeCString(ctx, callbackIdJsStr);
1193     return JS_NULL;
1194 }
1195 
JsHandleAnimator(JSContext * ctx,JSValueConst argv,const std::string & methodName)1196 JSValue JsHandleAnimator(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1197 {
1198     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1199     if (instance == nullptr) {
1200         return JS_NULL;
1201     }
1202     const char* args = JS_ToCString(ctx, argv);
1203     auto page = GetStagingPage(ctx);
1204     if (!page) {
1205         LOGE("JsHandleAnimator failed, page is null.");
1206         return JS_NULL;
1207     }
1208     auto resultAnimator = JSValue();
1209     if (methodName == ANIMATOR_CREATE_ANIMATOR || methodName == ANIMATOR_CREATE) {
1210         int32_t bridgeId = AnimatorBridgeUtils::JsCreateBridgeId();
1211         resultAnimator = AnimatorBridgeUtils::CreateAnimatorContext(ctx, page->GetPageId(), bridgeId);
1212         auto animatorBridge = AceType::MakeRefPtr<AnimatorBridge>(ctx, resultAnimator);
1213         auto task = AceType::MakeRefPtr<AnimatorTaskCreate>(animatorBridge, args);
1214         page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
1215     }
1216     return resultAnimator;
1217 }
1218 
JsAddListener(JSContext * ctx,JSValueConst argv)1219 JSValue JsAddListener(JSContext* ctx, JSValueConst argv)
1220 {
1221     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1222     if (instance == nullptr) {
1223         return JS_NULL;
1224     }
1225     JSPropertyEnum* pTab = nullptr;
1226     uint32_t len = 0;
1227     if (JS_IsObject(argv) && JS_IsArray(ctx, argv)) {
1228         JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1229         if (len == 0) {
1230             js_free(ctx, pTab);
1231             return JS_NULL;
1232         }
1233         JSValue jsListenerId = JS_GetProperty(ctx, argv, pTab[0].atom);
1234         const char* listenerId = JS_ToCString(ctx, jsListenerId);
1235         auto mediaQuery = instance->GetDelegate()->GetMediaQueryInfoInstance();
1236         if (mediaQuery) {
1237             mediaQuery->SetListenerId(std::string(listenerId));
1238         }
1239         JS_FreeCString(ctx, listenerId);
1240         JS_FreeValue(ctx, jsListenerId);
1241         js_free(ctx, pTab);
1242     }
1243     return JS_NULL;
1244 }
1245 
JsParseCallbackResult(JSContext * ctx,JSValueConst jsResult,const std::string & key,std::string & result)1246 void JsParseCallbackResult(JSContext* ctx, JSValueConst jsResult, const std::string& key, std::string& result)
1247 {
1248     ScopedString args(ctx, jsResult);
1249     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(args.get());
1250     if (argsPtr != nullptr && argsPtr->GetValue(key) != nullptr) {
1251         if (argsPtr->GetValue(key)->IsString()) {
1252             result = argsPtr->GetValue(key)->GetString();
1253         } else if (argsPtr->GetValue(key)->IsNumber()) {
1254             result = argsPtr->GetValue(key)->ToString();
1255         }
1256     }
1257 }
1258 
JsHandleCallback(JSContext * ctx,JSValueConst argv,const std::string & methodName)1259 JSValue JsHandleCallback(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1260 {
1261     if (methodName == CALLBACK_NATIVE) {
1262         if (JS_IsObject(argv) && JS_IsArray(ctx, argv)) {
1263             JSValue jsCallbackId = JS_GetPropertyUint32(ctx, argv, 0);
1264             JSValue jsResult = JS_GetPropertyUint32(ctx, argv, 1);
1265             const char* callbackId = JS_ToCString(ctx, jsCallbackId);
1266             std::string result = JS_ToCString(ctx, jsResult);
1267             JsParseCallbackResult(ctx, jsResult, KEY_STEPPER_PENDING_INDEX, result);
1268             auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1269             ACE_DCHECK(instance);
1270             instance->GetDelegate()->SetCallBackResult(std::string(callbackId), result);
1271 
1272             JS_FreeCString(ctx, callbackId);
1273             JS_FreeValue(ctx, jsCallbackId);
1274             JS_FreeValue(ctx, jsResult);
1275         }
1276     } else if (methodName == APP_DESTROY_FINISH) {
1277         LOGD("JsHandleCallback: appDestroyFinish should release resource here");
1278     } else {
1279         LOGW("internal.jsResult not support method = %{private}s", methodName.c_str());
1280     }
1281     js_std_loop(ctx);
1282     return JS_NULL;
1283 }
1284 
JsHandleImage(JSContext * ctx,JSValueConst argv)1285 JSValue JsHandleImage(JSContext* ctx, JSValueConst argv)
1286 {
1287     auto src = JsParseRouteUrl(ctx, argv, "src");
1288     auto success = JsParseRouteUrl(ctx, argv, "success");
1289     auto fail = JsParseRouteUrl(ctx, argv, "fail");
1290 
1291     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1292     if (instance == nullptr) {
1293         return JS_NULL;
1294     }
1295 
1296     auto&& callback = [instance, success, fail](bool callbackType, int32_t width, int32_t height) {
1297         if (callbackType) {
1298             instance->CallJs(success,
1299                 std::string("{\"width\":")
1300                     .append(std::to_string(width))
1301                     .append(", \"height\":")
1302                     .append(std::to_string(height))
1303                     .append("}"),
1304                 false);
1305         } else {
1306             instance->CallJs(fail, std::string("\"fail\",null"), false);
1307         }
1308     };
1309     instance->GetDelegate()->HandleImage(src, callback);
1310     return JS_NULL;
1311 }
1312 
ParseResourceStringParam(std::string & str,const char * paramName,JSContext * ctx,const JSValue & jsObject)1313 bool ParseResourceStringParam(std::string& str, const char* paramName, JSContext* ctx, const JSValue& jsObject)
1314 {
1315     if (JS_IsObject(jsObject)) {
1316         JSValue strValue = JS_GetPropertyStr(ctx, jsObject, paramName);
1317         if (JS_IsString(strValue)) {
1318             ScopedString uriValueStr(ctx, strValue);
1319             str = uriValueStr.get();
1320             return true;
1321         }
1322         JS_FreeValue(ctx, strValue);
1323     }
1324     return false;
1325 }
1326 
ParseResourceNumberParam(int32_t & num,const char * paramName,JSContext * ctx,const JSValue & jsObject)1327 bool ParseResourceNumberParam(int32_t& num, const char* paramName, JSContext* ctx, const JSValue& jsObject)
1328 {
1329     if (JS_IsObject(jsObject)) {
1330         JSValue numValue = JS_GetPropertyStr(ctx, jsObject, paramName);
1331         if (JS_IsUndefined(numValue)) {
1332             JS_FreeValue(ctx, numValue);
1333             return false;
1334         }
1335         ScopedString numValueStr(ctx, numValue);
1336         num = ParseResourceInputNumberParam(numValueStr.get());
1337         return true;
1338     }
1339     return false;
1340 }
1341 
ParseResourceParam(std::string & uri,int32_t & position,int32_t & length,JSContext * ctx,const JSValue & jsObject)1342 void ParseResourceParam(std::string& uri, int32_t& position, int32_t& length, JSContext* ctx, const JSValue& jsObject)
1343 {
1344     ParseResourceStringParam(uri, READ_KEY_URI, ctx, jsObject);
1345     ParseResourceNumberParam(position, READ_KEY_POSITION, ctx, jsObject);
1346     ParseResourceNumberParam(length, READ_KEY_LENGTH, ctx, jsObject);
1347 }
1348 
JsReadArrayBuffer(JSContext * ctx,JSValueConst argv)1349 JSValue JsReadArrayBuffer(JSContext* ctx, JSValueConst argv)
1350 {
1351     if (!JS_IsObject(argv) || !JS_IsArray(ctx, argv)) {
1352         LOGE("JsReadArrayBuffer: argv is not illegal");
1353         return JS_NULL;
1354     }
1355 
1356     JSPropertyEnum* pTab = nullptr;
1357     uint32_t len = 0;
1358     JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1359     if (len < ARGS_READ_RESOURCE_LENGTH) {
1360         LOGE("JsReadArrayBuffer: invalid callback value");
1361         js_free(ctx, pTab);
1362         return JS_EXCEPTION;
1363     }
1364 
1365     JSValue jsObject = JS_GetProperty(ctx, argv, pTab[0].atom);
1366     std::string uri;
1367     int32_t position = 1;
1368     int32_t length = MAX_READ_TEXT_LENGTH;
1369     ParseResourceParam(uri, position, length, ctx, jsObject);
1370     JSValue jsCallbackId = JS_GetProperty(ctx, argv, pTab[1].atom);
1371     JS_FreeValue(ctx, jsObject);
1372     js_free(ctx, pTab);
1373     ScopedString callbackId(ctx, jsCallbackId);
1374     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1375     std::smatch result;
1376     if (!std::regex_match(uri, result, URI_PATTERN)) {
1377         LOGE("JsReadArrayBuffer file uri pattern not correct");
1378         instance->CallJs(callbackId.get(),
1379             R"({"arguments":["file uri pattern not correct",202],"method":"fail"})");
1380         JS_FreeValue(ctx, jsCallbackId);
1381         return JS_NULL;
1382     }
1383 
1384     std::vector<uint8_t> binaryContent;
1385     if (!(instance->GetDelegate()->GetResourceData(uri, binaryContent))) {
1386         instance->CallJs(callbackId.get(),
1387             R"({"arguments":["read file failed",301],"method":"fail"})");
1388         JS_FreeValue(ctx, jsCallbackId);
1389         return JS_NULL;
1390     }
1391 
1392     auto fileLength = static_cast<int32_t>(binaryContent.size());
1393     if ((position > fileLength) || (position <= 0) || (length <= 0)) {
1394         instance->CallJs(callbackId.get(),
1395             R"({"arguments":["wrong start position or wrong read length", 202],"method":"fail"})");
1396         JS_FreeValue(ctx, jsCallbackId);
1397         return JS_NULL;
1398     }
1399 
1400     length = position + length - 1 > fileLength ? fileLength - position + 1 : length;
1401     JSValue binaryData = JS_NewObject(ctx);
1402     JSValue binaryArray = JS_NewArrayBufferCopy(ctx, &binaryContent[position - 1], length);
1403     JS_SetPropertyStr(ctx, binaryData, "buffer", binaryArray);
1404     instance->CallJs(callbackId.get(), R"({"arguments":["read array buffer success"],"method":"success"})");
1405     js_std_loop(ctx);
1406     return binaryData;
1407 }
1408 
JsReadText(JSContext * ctx,JSValueConst argv)1409 JSValue JsReadText(JSContext* ctx, JSValueConst argv)
1410 {
1411     if (!JS_IsObject(argv) || !JS_IsArray(ctx, argv)) {
1412         LOGE("JsReadText: argv is not illegal");
1413         return JS_NULL;
1414     }
1415 
1416     JSPropertyEnum* pTab = nullptr;
1417     uint32_t len = 0;
1418     JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1419     if (len < ARGS_READ_RESOURCE_LENGTH) {
1420         LOGE("JsReadText: invalid callback value");
1421         js_free(ctx, pTab);
1422         return JS_EXCEPTION;
1423     }
1424 
1425     JSValue jsObject = JS_GetProperty(ctx, argv, pTab[0].atom);
1426     std::string uri;
1427     ParseResourceStringParam(uri, READ_KEY_URI, ctx, jsObject);
1428     JSValue jsCallbackId = JS_GetProperty(ctx, argv, pTab[1].atom);
1429     ScopedString callbackId(ctx, jsCallbackId);
1430     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1431     std::smatch result;
1432     if (!std::regex_match(uri, result, URI_PATTERN)) {
1433         instance->CallJs(callbackId.get(),
1434             R"({"arguments":["file uri pattern not correct",202],"method":"fail"})");
1435         JS_FreeValue(ctx, jsCallbackId);
1436         JS_FreeValue(ctx, jsObject);
1437         js_free(ctx, pTab);
1438         return JS_NULL;
1439     }
1440 
1441     std::string fileText;
1442     if (!(instance->GetDelegate()->GetResourceData(uri, fileText))) {
1443         instance->CallJs(callbackId.get(), R"({"arguments":["read file failed",301],"method":"fail"})");
1444         JS_FreeValue(ctx, jsCallbackId);
1445         JS_FreeValue(ctx, jsObject);
1446         js_free(ctx, pTab);
1447         return JS_NULL;
1448     }
1449 
1450     int32_t position = 0;
1451     int32_t length = 0;
1452     auto fileLength = ParseUtf8TextLength(fileText);
1453     if (!ParseResourceNumberParam(position, READ_KEY_POSITION, ctx, jsObject)) {
1454         position = 1;
1455     }
1456 
1457     if (!ParseResourceNumberParam(length, READ_KEY_LENGTH, ctx, jsObject) || (length > fileLength - position + 1)) {
1458         length = (fileLength - position + 1 <= 0) ? 0 : fileLength - position + 1;
1459     }
1460 
1461     if (fileLength == 0) {
1462         if ((position <= 0) || (length < 0)) {
1463             instance->CallJs(callbackId.get(),
1464                 R"({"arguments":["wrong start position or wrong read length",202],"method":"fail"})");
1465             JS_FreeValue(ctx, jsCallbackId);
1466             JS_FreeValue(ctx, jsObject);
1467             js_free(ctx, pTab);
1468             return JS_NULL;
1469         }
1470     } else {
1471         if ((position > fileLength) || (position <= 0) || (length < 0)) {
1472             instance->CallJs(callbackId.get(),
1473                 R"({"arguments":["wrong start position or wrong read length",202],"method":"fail"})");
1474             JS_FreeValue(ctx, jsCallbackId);
1475             JS_FreeValue(ctx, jsObject);
1476             js_free(ctx, pTab);
1477             return JS_NULL;
1478         }
1479 
1480         auto substrPos = ParseUtf8TextSubstrStartPos(fileText, position);
1481         auto substrEndPos = ParseUtf8TextSubstrEndPos(fileText, position + length - 1);
1482         if (substrPos - 1 < 0 || substrEndPos - substrPos < 0) {
1483             LOGE("JsReadText: Invalid value of substrPos: %{public}d and substrEndPos: %{public}d", substrPos,
1484                 substrEndPos);
1485             return JS_NULL;
1486         }
1487         fileText =
1488             fileText.substr(static_cast<uint32_t>(substrPos - 1), static_cast<uint32_t>(substrEndPos - substrPos + 1));
1489         HandleEscapeCharaterInUtf8TextForJson(fileText);
1490     }
1491 
1492     instance->CallJs(callbackId.get(),
1493         std::string("{\"arguments\":[").append("{\"text\":\"").append(fileText).append("\"}],\"method\":\"success\"}"),
1494         false);
1495     JS_FreeValue(ctx, jsCallbackId);
1496     JS_FreeValue(ctx, jsObject);
1497     js_std_loop(ctx);
1498     js_free(ctx, pTab);
1499     return JS_NULL;
1500 }
1501 
JsHandleReadResource(JSContext * ctx,JSValueConst argv,const std::string & methodName)1502 JSValue JsHandleReadResource(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1503 {
1504     LOGD("JsHandleReadResource");
1505     if (methodName == READ_TEXT) {
1506         return JsReadText(ctx, argv);
1507     } else if (methodName == READ_ARRAY_BUFFER) {
1508         return JsReadArrayBuffer(ctx, argv);
1509     } else {
1510         LOGW("system.resource not support method = %{private}s", methodName.c_str());
1511     }
1512     return JS_NULL;
1513 }
1514 
JsSetTimer(JSContext * ctx,JSValueConst argv,bool isInterval)1515 void JsSetTimer(JSContext* ctx, JSValueConst argv, bool isInterval)
1516 {
1517     JSPropertyEnum* pTab = nullptr;
1518     uint32_t len = 0;
1519     if (JS_IsObject(argv) && JS_IsArray(ctx, argv)) {
1520         JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1521         if (len < 2) {
1522             LOGW("JsSetTimer: invalid callback value");
1523             return;
1524         }
1525 
1526         JSValue jsCallBackId = JS_GetProperty(ctx, argv, pTab[0].atom);
1527         JSValue jsDelay = JS_GetProperty(ctx, argv, pTab[1].atom);
1528         const char* callBackId = JS_ToCString(ctx, jsCallBackId);
1529         const char* delay = JS_ToCString(ctx, jsDelay);
1530         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1531         ACE_DCHECK(instance);
1532         LOGD("JsSetTimer callbackId: %{private}s, delay: %{private}s", callBackId, delay);
1533         instance->GetDelegate()->WaitTimer(std::string(callBackId), std::string(delay), isInterval, true);
1534 
1535         JS_FreeCString(ctx, callBackId);
1536         JS_FreeCString(ctx, delay);
1537         JS_FreeValue(ctx, jsCallBackId);
1538         JS_FreeValue(ctx, jsDelay);
1539         js_free(ctx, pTab);
1540     }
1541 }
1542 
JsClearTimeout(JSContext * ctx,JSValueConst argv)1543 void JsClearTimeout(JSContext* ctx, JSValueConst argv)
1544 {
1545     JSPropertyEnum* pTab = nullptr;
1546     uint32_t len = 0;
1547     if (JS_IsObject(argv) && JS_IsArray(ctx, argv)) {
1548         JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1549         if (len < 1) {
1550             LOGW("JsClearTimeout: invalid callback value");
1551             return;
1552         }
1553 
1554         JSValue jsCallBackId = JS_GetProperty(ctx, argv, pTab[0].atom);
1555         const char* callBackId = JS_ToCString(ctx, jsCallBackId);
1556         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1557         ACE_DCHECK(instance);
1558         LOGD("ClearTimeOut callBackId: %{private}s", callBackId);
1559         instance->GetDelegate()->ClearTimer(std::string(callBackId));
1560 
1561         JS_FreeCString(ctx, callBackId);
1562         JS_FreeValue(ctx, jsCallBackId);
1563         js_free(ctx, pTab);
1564     }
1565     js_std_loop(ctx);
1566 }
1567 
JsSetLocale(JSContext * ctx,JSValueConst argv)1568 JSValue JsSetLocale(JSContext* ctx, JSValueConst argv)
1569 {
1570     ScopedString args(ctx, argv);
1571     std::unique_ptr<JsonValue> localeJson = JsonUtil::ParseJsonString(args.get());
1572     if (localeJson) {
1573         std::string language;
1574         if (localeJson->GetValue(LOCALE_LANGUAGE) != nullptr && localeJson->GetValue(LOCALE_LANGUAGE)->IsString()) {
1575             language = localeJson->GetValue(LOCALE_LANGUAGE)->GetString();
1576         }
1577         std::string countryOrRegion;
1578         if (localeJson->GetValue(LOCALE_COUNTRY_OR_REGION) != nullptr &&
1579             localeJson->GetValue(LOCALE_COUNTRY_OR_REGION)->IsString()) {
1580             countryOrRegion = localeJson->GetValue(LOCALE_COUNTRY_OR_REGION)->GetString();
1581         }
1582         if (!countryOrRegion.empty() && !language.empty()) {
1583             auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1584             ACE_DCHECK(instance);
1585             instance->ChangeLocale(language, countryOrRegion);
1586         }
1587     }
1588     return JS_NULL;
1589 }
1590 
JsHandleSetTimeout(JSContext * ctx,JSValueConst argv,const std::string & methodName)1591 JSValue JsHandleSetTimeout(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1592 {
1593     if (methodName == SET_TIMEOUT) {
1594         JsSetTimer(ctx, argv, false);
1595     } else if (methodName == CLEAR_TIMEOUT || methodName == CLEAR_INTERVAL) {
1596         JsClearTimeout(ctx, argv);
1597     } else if (methodName == SET_INTERVAL) {
1598         JsSetTimer(ctx, argv, true);
1599     } else {
1600         LOGW("Unsupported method for timer module!");
1601         return JS_NULL;
1602     }
1603     return JS_NULL;
1604 }
1605 
JsHandleMediaQuery(JSContext * ctx,JSValueConst argv,const std::string & methodName)1606 JSValue JsHandleMediaQuery(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1607 {
1608     if (methodName == ADD_LISTENER) {
1609         JsAddListener(ctx, argv);
1610     } else if (methodName == GET_DEVICE_TYPE) {
1611         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1612         if (instance != nullptr) {
1613             auto mediaQuery = instance->GetDelegate()->GetMediaQueryInfoInstance();
1614             if (mediaQuery) {
1615                 return JS_NewString(ctx, mediaQuery->GetDeviceType().c_str());
1616             }
1617         }
1618     } else {
1619         LOGW("system.mediaquery not support method = %{private}s", methodName.c_str());
1620     }
1621     return JS_NULL;
1622 }
1623 
GetAppInfo(JSContext * ctx)1624 JSValue GetAppInfo(JSContext* ctx)
1625 {
1626     QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1627     JSValue appID = JS_NewString(ctx, instance->GetDelegate()->GetAppID().c_str());
1628     JSValue appName = JS_NewString(ctx, instance->GetDelegate()->GetAppName().c_str());
1629     JSValue versionName = JS_NewString(ctx, instance->GetDelegate()->GetVersionName().c_str());
1630     JSValue versionCode = JS_NewInt32(ctx, instance->GetDelegate()->GetVersionCode());
1631 
1632     JSValue resData = JS_NewObject(ctx);
1633     JS_SetPropertyStr(ctx, resData, "appID", appID);
1634     JS_SetPropertyStr(ctx, resData, "appName", appName);
1635     JS_SetPropertyStr(ctx, resData, "versionName", versionName);
1636     JS_SetPropertyStr(ctx, resData, "versionCode", versionCode);
1637 
1638     return resData;
1639 }
1640 
Terminate(JSContext * ctx)1641 JSValue Terminate(JSContext* ctx)
1642 {
1643     QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1644     WeakPtr<PipelineBase> pipelineContextWeak = instance->GetDelegate()->GetPipelineContext();
1645     auto uiTaskExecutor = instance->GetDelegate()->GetUiTask();
1646     uiTaskExecutor.PostTask([pipelineContextWeak]() mutable {
1647         auto pipelineContext = pipelineContextWeak.Upgrade();
1648         if (pipelineContext) {
1649             pipelineContext->Finish();
1650         }
1651     });
1652     return JS_NULL;
1653 }
1654 
ParseFullWindowParams(JSContext * ctx,JSValue params,std::string & duration)1655 void ParseFullWindowParams(JSContext* ctx, JSValue params, std::string& duration)
1656 {
1657     JSPropertyEnum* tab = nullptr;
1658     uint32_t paramLen = 0;
1659     if (JS_IsObject(params)) {
1660         JS_GetOwnPropertyNames(ctx, &tab, &paramLen, params, JS_GPN_STRING_MASK);
1661         const char* jsDurationKey = JS_AtomToCString(ctx, tab[0].atom);
1662         if (jsDurationKey == nullptr) {
1663             JS_FreeAtom(ctx, tab[0].atom);
1664             js_free(ctx, tab);
1665             LOGE("jsDurationKey is null.");
1666             return;
1667         }
1668         if (std::strcmp(jsDurationKey, "duration") == 0) {
1669             JSValue valObject = JS_GetProperty(ctx, params, tab[0].atom);
1670             if (JS_IsString(valObject) || JS_IsNumber(valObject)) {
1671                 ScopedString styleVal(ctx, valObject);
1672                 const char* valDuration = styleVal.get();
1673                 duration = valDuration;
1674             }
1675             JS_FreeValue(ctx, valObject);
1676         }
1677         JS_FreeAtom(ctx, tab[0].atom);
1678         JS_FreeCString(ctx, jsDurationKey);
1679     }
1680     js_free(ctx, tab);
1681 }
1682 
RequestFullWindow(JSContext * ctx,JSValueConst argv)1683 JSValue RequestFullWindow(JSContext* ctx, JSValueConst argv)
1684 {
1685     JSPropertyEnum* pTab = nullptr;
1686     uint32_t len = 0;
1687     int32_t duration = -1; // default scene
1688     if (JS_IsObject(argv) && JS_IsArray(ctx, argv)) {
1689         JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1690         if (len < ARGS_FULL_WINDOW_LENGTH) {
1691             LOGW("RequestFullWindow: invalid callback value");
1692             js_free(ctx, pTab);
1693             return JS_NULL;
1694         }
1695 
1696         if (len == CUSTOM_FULL_WINDOW_LENGTH) {
1697             JSValue jsDuration = JS_GetProperty(ctx, argv, pTab[0].atom);
1698             std::string valDuration;
1699             ParseFullWindowParams(ctx, jsDuration, valDuration);
1700             if (!valDuration.empty()) {
1701                 duration = StringToInt(valDuration);
1702             }
1703             if (duration < 0) {
1704                 duration = -1; // default scene
1705             }
1706             JS_FreeValue(ctx, jsDuration);
1707         }
1708         js_free(ctx, pTab);
1709     }
1710     QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1711     WeakPtr<PipelineBase> pipelineContextWeak = instance->GetDelegate()->GetPipelineContext();
1712     auto uiTaskExecutor = instance->GetDelegate()->GetUiTask();
1713     uiTaskExecutor.PostTask([pipelineContextWeak, duration]() mutable {
1714         auto pipelineContext = pipelineContextWeak.Upgrade();
1715         if (pipelineContext) {
1716             pipelineContext->RequestFullWindow(duration);
1717         }
1718     });
1719     return JS_NULL;
1720 }
1721 
GetPackageInfoCallback(JSContext * ctx,JSValueConst jsMessage,const char * callbackId)1722 void GetPackageInfoCallback(JSContext* ctx, JSValueConst jsMessage, const char* callbackId)
1723 {
1724     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1725     if (!JS_IsObject(jsMessage)) {
1726         LOGE("GetPackageInfoCallback: jsMessage is not Object");
1727         instance->CallJs(
1728             callbackId, std::string("{\"arguments\":[\"jsMessage is not Object\",200],\"method\":\"fail\"}"), false);
1729         return;
1730     }
1731     JSValue jsPackageName = JS_GetPropertyStr(ctx, jsMessage, APP_PACKAGE_NAME);
1732     if (!JS_IsString(jsPackageName)) {
1733         LOGE("GetPackageInfoCallback: package name is not String");
1734         instance->CallJs(callbackId,
1735             std::string("{\"arguments\":[\"packageName is not available string\",202],\"method\":\"fail\"}"), false);
1736     } else {
1737         ScopedString packageName(ctx, jsPackageName);
1738         AceBundleInfo bundleInfo;
1739         if (AceApplicationInfo::GetInstance().GetBundleInfo(packageName.get(), bundleInfo)) {
1740             auto infoList = JsonUtil::Create(true);
1741             infoList->Put("versionName", bundleInfo.versionName.c_str());
1742             infoList->Put("versionCode", std::to_string(bundleInfo.versionCode).c_str());
1743             instance->CallJs(callbackId,
1744                 std::string("{\"arguments\":[").append(infoList->ToString()).append("],\"method\":\"success\"}"),
1745                 false);
1746         } else {
1747             LOGE("can not get info by GetBundleInfo");
1748             instance->CallJs(
1749                 callbackId, std::string("{\"arguments\":[\"can not get info\",200],\"method\":\"fail\"}"), false);
1750         }
1751     }
1752     JS_FreeValue(ctx, jsPackageName);
1753 }
1754 
GetPackageInfo(JSContext * ctx,JSValueConst argv)1755 JSValue GetPackageInfo(JSContext* ctx, JSValueConst argv)
1756 {
1757     if (!JS_IsObject(argv)) {
1758         LOGE("GetPackageInfo: argv is not Object");
1759         return JS_NULL;
1760     }
1761 
1762     if (!JS_IsArray(ctx, argv)) {
1763         LOGE("GetPackageInfo: argv is not Array");
1764         return JS_NULL;
1765     }
1766 
1767     JSPropertyEnum* pTab = nullptr;
1768     uint32_t len = 0;
1769 
1770     JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1771     if (len < 2) {
1772         LOGE("GetPackageInfo: invalid callback value");
1773         js_free(ctx, pTab);
1774         return JS_EXCEPTION;
1775     }
1776 
1777     JSValue jsMessage = JS_GetProperty(ctx, argv, pTab[0].atom);
1778     JSValue jsCallbackId = JS_GetProperty(ctx, argv, pTab[1].atom);
1779     const char* callbackId = JS_ToCString(ctx, jsCallbackId);
1780     LOGD("system app getPackageInfo callBackID is %{public}s", callbackId);
1781     GetPackageInfoCallback(ctx, jsMessage, callbackId);
1782 
1783     JS_FreeCString(ctx, callbackId);
1784     JS_FreeValue(ctx, jsMessage);
1785     JS_FreeValue(ctx, jsCallbackId);
1786     js_free(ctx, pTab);
1787 
1788     return JS_NULL;
1789 }
1790 
SetScreenOnVisible(JSContext * ctx,JSValueConst argv)1791 JSValue SetScreenOnVisible(JSContext* ctx, JSValueConst argv)
1792 {
1793     if (!JS_IsObject(argv) || !JS_IsArray(ctx, argv)) {
1794         LOGE("SetScreenOnVisible: argv is not illegal");
1795         return JS_NULL;
1796     }
1797     JSPropertyEnum* pTab = nullptr;
1798     uint32_t len = 0;
1799     JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1800     if (len < 2) {
1801         LOGE("SetScreenOnVisible: invalid callback value");
1802         js_free(ctx, pTab);
1803         return JS_EXCEPTION;
1804     }
1805     JSValue jsObject = JS_GetProperty(ctx, argv, pTab[0].atom);
1806     std::string flag = "false";
1807     if (JS_IsObject(jsObject)) {
1808         JSValue flagValue = JS_GetPropertyStr(ctx, jsObject, APP_SCREEN_ON_VISIBLE_FLAG);
1809         if (JS_IsBool(flagValue)) {
1810             ScopedString flagValueStr(ctx, flagValue);
1811             flag = flagValueStr.get();
1812         }
1813     }
1814     JSValue jsCallbackId = JS_GetProperty(ctx, argv, pTab[1].atom);
1815     ScopedString callbackId(ctx, jsCallbackId);
1816     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1817     if (StringToBool(flag)) {
1818         instance->CallJs(callbackId.get(), R"({"arguments":[], "method":"success"})");
1819     } else {
1820         instance->CallJs(
1821             callbackId.get(), R"({"arguments":["fail to set false flag in rich platform", 200],"method":"fail"})");
1822     }
1823     JS_FreeValue(ctx, jsObject);
1824     JS_FreeValue(ctx, jsCallbackId);
1825     js_free(ctx, pTab);
1826     return JS_NULL;
1827 }
1828 
SetSwipeToDismiss(JSContext * ctx,JSValueConst argv)1829 JSValue SetSwipeToDismiss(JSContext* ctx, JSValueConst argv)
1830 {
1831     if (!JS_IsObject(argv) || !JS_IsArray(ctx, argv)) {
1832         LOGE("SetSwipeToDismiss: argv is not illegal");
1833         return JS_NULL;
1834     }
1835 
1836     JSPropertyEnum* pTab = nullptr;
1837     uint32_t len = 0;
1838     JS_GetOwnPropertyNames(ctx, &pTab, &len, argv, JS_GPN_STRING_MASK);
1839     if (len < 2) {
1840         LOGE("SetSwipeToDismiss: invalid callback value");
1841         js_free(ctx, pTab);
1842         return JS_EXCEPTION;
1843     }
1844 
1845     bool forbidQuit = false;
1846     JSValue jsObject = JS_GetProperty(ctx, argv, pTab[0].atom);
1847     if (JS_IsBool(jsObject)) {
1848         forbidQuit = JS_ToBool(ctx, jsObject);
1849     }
1850 
1851     QjsEngineInstance* instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1852     WeakPtr<PipelineContext> pipelineContextWeak =
1853         AceType::DynamicCast<PipelineContext>(instance->GetDelegate()->GetPipelineContext());
1854     auto uiTaskExecutor = instance->GetDelegate()->GetUiTask();
1855     uiTaskExecutor.PostTask([pipelineContextWeak, forbidQuit]() mutable {
1856         auto pipelineContext = pipelineContextWeak.Upgrade();
1857         if (pipelineContext) {
1858             pipelineContext->SetForbidPlatformQuit(forbidQuit);
1859         }
1860     });
1861 
1862     JS_FreeValue(ctx, jsObject);
1863     js_free(ctx, pTab);
1864     return JS_NULL;
1865 }
1866 
JsHandleAppApi(JSContext * ctx,JSValueConst argv,const std::string & methodName)1867 JSValue JsHandleAppApi(JSContext* ctx, JSValueConst argv, const std::string& methodName)
1868 {
1869     if (methodName == APP_GET_INFO) {
1870         return GetAppInfo(ctx);
1871     } else if (methodName == APP_TERMINATE) {
1872         return Terminate(ctx);
1873     } else if (methodName == APP_GET_PACKAGE_INFO) {
1874         return GetPackageInfo(ctx, argv);
1875     } else if (methodName == APP_REQUEST_FULL_WINDOW) {
1876         return RequestFullWindow(ctx, argv);
1877     } else if (methodName == APP_SCREEN_ON_VISIBLE) {
1878         return SetScreenOnVisible(ctx, argv);
1879     } else if (methodName == APP_SET_SWIPE_TO_DISMISS) {
1880         return SetSwipeToDismiss(ctx, argv);
1881     } else {
1882         return JS_NULL;
1883     }
1884 }
1885 
JsGetDeviceInfo(JSContext * ctx,JSValueConst argv)1886 JSValue JsGetDeviceInfo(JSContext* ctx, JSValueConst argv)
1887 {
1888     const char* callbackId = JS_ToCString(ctx, argv);
1889     if (callbackId == nullptr) {
1890         LOGE("system device getInfo callBackID is null");
1891     } else {
1892         LOGD("system device getInfo callBackID = %{public}s", callbackId);
1893         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1894         std::pair<std::string, bool> ret = PluginBridge::GetDeviceInfo();
1895         if (ret.second) {
1896             instance->CallJs(callbackId,
1897                 std::string("{\"arguments\":[").append(ret.first).append("],\"method\":\"success\"}"), false);
1898         } else {
1899             instance->CallJs(callbackId,
1900                 std::string("{\"arguments\":[").append(ret.first).append(",200],\"method\":\"fail\"}"), false);
1901         }
1902         JS_FreeCString(ctx, callbackId);
1903     }
1904 
1905     return JS_NULL;
1906 }
1907 
GetLocale(JSContext * ctx)1908 JSValue GetLocale(JSContext* ctx)
1909 {
1910     JSValue language = JS_NewString(ctx, AceApplicationInfo::GetInstance().GetLanguage().c_str());
1911     JSValue countryOrRegion = JS_NewString(ctx, AceApplicationInfo::GetInstance().GetCountryOrRegion().c_str());
1912     JSValue dir = JS_NewString(
1913         ctx, AceApplicationInfo::GetInstance().IsRightToLeft() ? LOCALE_TEXT_DIR_RTL : LOCALE_TEXT_DIR_LTR);
1914     JSValue unicodeSetting = JS_NewString(ctx, AceApplicationInfo::GetInstance().GetUnicodeSetting().c_str());
1915 
1916     JSValue resData = JS_NewObject(ctx);
1917     JS_SetPropertyStr(ctx, resData, LOCALE_LANGUAGE, language);
1918     JS_SetPropertyStr(ctx, resData, LOCALE_COUNTRY_OR_REGION, countryOrRegion);
1919     JS_SetPropertyStr(ctx, resData, LOCALE_TEXT_DIR, dir);
1920     JS_SetPropertyStr(ctx, resData, LOCALE_UNICODE_SETTING, unicodeSetting);
1921 
1922     return resData;
1923 }
1924 
JsCallComponent(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)1925 JSValue JsCallComponent(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
1926 {
1927     if ((argv == nullptr) || (argc != 3)) {
1928         LOGE("argc error, argc = %{private}d", argc);
1929         return JS_NULL;
1930     }
1931     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1932     if (instance == nullptr) {
1933         LOGE("JsCallComponent failed, instance is null.");
1934         return JS_NULL;
1935     }
1936     auto page = GetRunningPage(ctx);
1937     if (!page) {
1938         LOGE("JsCallComponent failed, page is null.");
1939         return JS_NULL;
1940     }
1941     int32_t nodeId;
1942     JS_ToInt32(ctx, &nodeId, argv[0]);
1943     nodeId = (nodeId == 0) ? DOM_ROOT_NODE_ID_BASE + page->GetPageId() : nodeId;
1944     ScopedString methodName(ctx, argv[1]);
1945     ScopedString args(ctx, argv[2]);
1946     LOGD("nodeId = %{private}d, methodName = %{private}s, args = %{private}s", nodeId, methodName.get(), args.get());
1947     auto engine = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
1948     if (engine == nullptr) {
1949         return JS_NULL;
1950     }
1951     // handle canvas getContext
1952     if (std::strcmp(methodName.get(), "getContext") == 0) {
1953         auto bridge = AceType::DynamicCast<CanvasBridge>(page->GetBridgeById(nodeId));
1954         if (bridge) {
1955             bridge->HandleJsContext(ctx, nodeId, args.get(), engine);
1956             return bridge->GetRenderContext();
1957         }
1958         return JS_NULL;
1959     } else if (std::strcmp(methodName.get(), "toDataURL") == 0) {
1960         auto bridge = AceType::DynamicCast<CanvasBridge>(page->GetBridgeById(nodeId));
1961         if (bridge) {
1962             bridge->HandleToDataURL(ctx, nodeId, args.get());
1963             return bridge->GetDataURL();
1964         }
1965         return JS_NULL;
1966     } else if (std::strcmp(methodName.get(), "getScrollOffset") == 0) {
1967         // handle getScrollOffset method of scroll view, like div, stack and list.
1968         return ComponentApiBridge::JsGetScrollOffset(ctx, nodeId);
1969     } else if (std::strcmp(methodName.get(), "getBoundingClientRect") == 0) {
1970         return ComponentApiBridge::JsGetBoundingRect(ctx, nodeId);
1971     } else if (std::strcmp(methodName.get(), "getInspector") == 0) {
1972         return ComponentApiBridge::JsGetInspector(ctx, nodeId);
1973     } else if (std::strcmp(methodName.get(), "scrollTo") == 0) {
1974         ComponentApiBridge::JsScrollTo(ctx, args.get(), nodeId);
1975     } else if (std::strcmp(methodName.get(), "getXComponentContext") == 0) {
1976         auto bridge = AceType::DynamicCast<QjsXComponentBridge>(page->GetXComponentBridgeById(nodeId));
1977         if (bridge) {
1978             bridge->HandleContext(ctx, nodeId, args.get());
1979             return bridge->GetRenderContext();
1980         }
1981     } else if (std::strcmp(methodName.get(), "getXComponentSurfaceId") == 0) {
1982         return QjsXComponentBridge::JsGetXComponentSurfaceId(ctx, nodeId);
1983     } else if (std::strcmp(methodName.get(), "setXComponentSurfaceSize") == 0) {
1984         QjsXComponentBridge::JsSetXComponentSurfaceSize(ctx, args.get(), nodeId);
1985         return JS_NULL;
1986     }
1987 
1988     auto resultValue = JSValue();
1989     // handle animation animate method
1990     if (std::strcmp(methodName.get(), "animate") == 0) {
1991         resultValue = AnimationBridgeUtils::CreateAnimationContext(ctx, page->GetPageId(), nodeId);
1992         auto animationBridge = AceType::MakeRefPtr<AnimationBridge>(ctx, resultValue, nodeId);
1993         auto task = AceType::MakeRefPtr<AnimationBridgeTaskCreate>(animationBridge, args.get());
1994         page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimation>(nodeId, task));
1995     } else if (std::strcmp(methodName.get(), "currentOffset") == 0) {
1996         // handle list currentOffset method
1997         return ListBridge::JsGetCurrentOffset(ctx, nodeId);
1998     } else if (std::strcmp(methodName.get(), "getState") == 0) {
1999         // handle image animator getState method.
2000         return ImageAnimatorBridge::JsGetState(ctx, nodeId);
2001     } else if (std::strcmp(methodName.get(), "createIntersectionObserver") == 0) {
2002         return ComponentApiBridge::JsCreateObserver(ctx, args.get(), nodeId);
2003     } else if (std::strcmp(methodName.get(), "addChild") == 0) {
2004         auto sPage = GetStagingPage(ctx);
2005         if (sPage == nullptr) {
2006             return JS_EXCEPTION;
2007         }
2008         int32_t childNodeId = 0;
2009         std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args.get());
2010         if (argsValue && argsValue->IsArray()) {
2011             std::unique_ptr<JsonValue> cNodeId = argsValue->GetArrayItem(0)->GetValue("__nodeId");
2012             if (cNodeId && cNodeId->IsNumber()) {
2013                 childNodeId = cNodeId->GetInt();
2014             }
2015         }
2016         auto domDocument = sPage->GetDomDocument();
2017         if (domDocument) {
2018             RefPtr<DOMNode> node = domDocument->GetDOMNodeById(childNodeId);
2019             if (node == nullptr) {
2020                 LOGE("node is nullptr");
2021             }
2022             auto command = Referenced::MakeRefPtr<JsCommandAppendElement>(node ? node->GetTag() : "", childNodeId,
2023 			    nodeId);
2024             sPage->PushCommand(command);
2025             if (!sPage->CheckPageCreated() && sPage->GetCommandSize() > FRAGMENT_SIZE) {
2026                 sPage->FlushCommands();
2027             }
2028         }
2029     } else {
2030         page->PushCommand(Referenced::MakeRefPtr<JsCommandCallDomElementMethod>(nodeId, methodName.get(), args.get()));
2031     }
2032     // focus method should delayed util show attribute update.
2033     if (page->CheckPageCreated() && strlen(DOM_FOCUS) >= strlen(methodName.get()) &&
2034         strcmp(DOM_FOCUS, methodName.get()) != 0) {
2035         instance->GetDelegate()->TriggerPageUpdate(page->GetPageId(), true);
2036     }
2037     return resultValue;
2038 }
2039 
JsCallConfiguration(JSContext * ctx,const std::string & method,JSValueConst argv)2040 JSValue JsCallConfiguration(JSContext* ctx, const std::string& method, JSValueConst argv)
2041 {
2042     if (CONFIGURATION_GET_LOCALE == method) {
2043         return GetLocale(ctx);
2044     } else if (CONFIGURATION_SET_LOCALE == method) {
2045         return JsSetLocale(ctx, argv);
2046     }
2047     return JS_NULL;
2048 }
2049 
2050 
JsHandleOffscreenCanvas(JSContext * ctx,JSValueConst value,JSValueConst argv,const std::string & methodName)2051 JSValue JsHandleOffscreenCanvas(JSContext* ctx, JSValueConst value, JSValueConst argv, const std::string& methodName)
2052 {
2053     LOGD("JsHandleOffscreenCanvas: methodName = %{public}s", methodName.c_str());
2054 
2055     auto page = GetRunningPage(ctx);
2056     if (!page) {
2057         LOGE("JsHandleOffscreenCanvas failed, page is null.");
2058         return JS_NULL;
2059     }
2060 
2061     if (methodName == OFFSCREEN_CANVAS_CREATE) {
2062         int32_t width = JsParseIntParams(ctx, argv, "width");
2063         int32_t height = JsParseIntParams(ctx, argv, "height");
2064 
2065         auto bridge = AceType::MakeRefPtr<OffscreenCanvasBridge>(ctx, width, height);
2066         page->PushOffscreenCanvasBridge(bridge->bridgeId_, bridge);
2067 
2068         return bridge->GetBridge(ctx);
2069 
2070     } else {
2071         LOGE("JsHandleOffscreenCanvas: methodName not find");
2072     }
2073 
2074     return JS_NULL;
2075 }
JsHandleModule(std::string moduleName,std::string methodName,JSContext * ctx,JSValueConst value,JSValueConst * argv)2076 JSValue JsHandleModule(std::string moduleName, std::string methodName, JSContext* ctx, JSValueConst value,
2077     JSValueConst* argv)
2078 {
2079     static const LinearMapNode<JSValue (*)(JSContext*, JSValueConst, JSValueConst*,
2080         const std::string&)> jsHandleMap[] = {
2081             { "animation",
2082                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2083                     return JsHandleAnimationFrame(ctx, argv[1], methodName);
2084                 } },
2085             { "internal.jsResult",
2086                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2087                     return JsHandleCallback(ctx, argv[1], methodName);
2088                 } },
2089             { "ohos.animator",
2090                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2091                     return JsHandleAnimator(ctx, argv[1], methodName);
2092                 } },
2093             { "system.app",
2094                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2095                     return JsHandleAppApi(ctx, argv[1], methodName);
2096                 } },
2097             { "system.configuration",
2098                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2099                     return JsCallConfiguration(ctx, methodName, argv[1]);
2100                 } },
2101             { "system.device",
2102                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2103                     if (methodName == "getInfo") {
2104                         return JsGetDeviceInfo(ctx, argv[1]);
2105                     } else {
2106                         return JS_NULL;
2107                     }
2108                 } },
2109             { "system.image",
2110                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2111                     return JsHandleImage(ctx, argv[1]);
2112                 } },
2113             { "system.mediaquery",
2114                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2115                     return JsHandleMediaQuery(ctx, argv[1], methodName);
2116                 } },
2117             { "system.offscreenCanvas",
2118                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv,  const std::string& methodName) {
2119                     return JsHandleOffscreenCanvas(ctx, value, argv[1], methodName);
2120                 } },
2121             { "system.prompt",
2122                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2123                     return JsHandlePrompt(ctx, argv[1], methodName);
2124                 } },
2125             { "system.resource",
2126                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2127                     return JsHandleReadResource(ctx, argv[1], methodName);
2128                 } },
2129             { "system.router",
2130                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2131                     return JsHandlePageRoute(ctx, argv[1], methodName);
2132                 } },
2133             { "timer",
2134                 [](JSContext* ctx, JSValueConst value, JSValueConst* argv, const std::string& methodName) {
2135                     return JsHandleSetTimeout(ctx, argv[1], methodName);
2136                 } },
2137     };
2138 
2139     auto jsHandleIter = BinarySearchFindIndex(jsHandleMap, ArraySize(jsHandleMap), moduleName.c_str());
2140     if (jsHandleIter != -1) {
2141         return jsHandleMap[jsHandleIter].value(ctx, value, argv, methodName);
2142     }
2143 
2144     return JS_NULL;
2145 }
2146 
JsCallNative(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2147 JSValue JsCallNative(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2148 {
2149     ACE_SCOPED_TRACE("JsCallNative");
2150 
2151     if ((argv == nullptr) || (argc != 2)) {
2152         LOGE("the arg is error");
2153         return JS_EXCEPTION;
2154     }
2155 
2156     ScopedString moduleAndMethod(ctx, argv[0]);
2157     ScopedString args(ctx, argv[1]);
2158     LOGD("JsCallNative moduleAndMethod = %{private}s, args = %{private}s", moduleAndMethod.get(), args.get());
2159 
2160     std::unique_ptr<JsonValue> moduleAndMethodPtr = JsonUtil::ParseJsonString(moduleAndMethod.get());
2161     if (!moduleAndMethodPtr) {
2162         LOGE("Get moduleAndMethod from argv failed");
2163         return JS_NULL;
2164     }
2165 
2166     std::unique_ptr<JsonValue> modulePtr = moduleAndMethodPtr->GetValue("module");
2167     if (!modulePtr) {
2168         LOGE("Get module from moduleAndMethodPtr failed");
2169         return JS_NULL;
2170     }
2171 
2172     std::unique_ptr<JsonValue> methodPtr = moduleAndMethodPtr->GetValue("method");
2173     if (!methodPtr) {
2174         LOGE("Get method from moduleAndMethodPtr failed");
2175         return JS_NULL;
2176     }
2177 
2178     const std::string moduleName = modulePtr->GetString();
2179     const std::string methodName = methodPtr->GetString();
2180 
2181     LOGD("JsCallNative moduleName = %{private}s, methodName = %{private}s", moduleName.c_str(), methodName.c_str());
2182     js_std_loop(ctx);
2183     return JsHandleModule(moduleName, methodName, ctx, value, argv);
2184 }
2185 
2186 #if defined(ENABLE_JS_DEBUG) || defined(ENABLE_JS_DEBUG_PREVIEW)
JsCompileAndRunBundle(JSContext * ctx,JSValueConst thisVal,int argc,JSValueConst * argv)2187 JSValue JsCompileAndRunBundle(JSContext* ctx, JSValueConst thisVal, int argc, JSValueConst* argv)
2188 {
2189     ScopedString str(ctx, argv[0]);
2190     ScopedString url(ctx, argv[1]);
2191     JSValue CppToJSRet = JS_Eval(ctx, str.get(), strlen(str.get()), url.get(), JS_EVAL_TYPE_GLOBAL);
2192 
2193     if (JS_IsException(CppToJSRet)) {
2194         LOGE("Qjs JsCompileAndRunBundle FAILED !!");
2195         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::COMPILE_AND_RUN_BUNDLE_ERROR);
2196         return JS_NULL;
2197     }
2198 
2199     js_std_loop(ctx);
2200     return CppToJSRet;
2201 }
2202 #endif
2203 
ParseLogContent(JSContext * ctx,int32_t argc,JSValueConst * argv)2204 std::string ParseLogContent(JSContext* ctx, int32_t argc, JSValueConst* argv)
2205 {
2206     std::string formatStr = ScopedString(ctx, argv[0]).get();
2207     if (argc == 1 || formatStr.empty()) {
2208         return formatStr;
2209     }
2210     std::string ret;
2211     size_t len = formatStr.size();
2212     size_t pos = 0;
2213     int32_t count = 1;
2214     for (; pos < len; ++pos) {
2215         if (count >= argc) {
2216             break;
2217         }
2218         if (formatStr[pos] == '%') {
2219             if (pos + 1 >= len) {
2220                 break;
2221             }
2222             switch (formatStr[pos + 1]) {
2223                 case 's':
2224                 case 'j':
2225                 case 'd':
2226                 case 'O':
2227                 case 'o':
2228                 case 'i':
2229                 case 'f':
2230                 case 'c':
2231                     ret += ScopedString(ctx, argv[count++]).get();
2232                     ++pos;
2233                     break;
2234                 case '%':
2235                     ret += formatStr[pos];
2236                     ++pos;
2237                     break;
2238                 default:
2239                     ret += formatStr[pos];
2240                     break;
2241             }
2242         } else {
2243             ret += formatStr[pos];
2244         }
2245     }
2246     if (pos < len) {
2247         ret += formatStr.substr(pos, len - pos);
2248     }
2249     return ret;
2250 }
2251 
AppLogPrint(JSContext * ctx,JsLogLevel level,JSValueConst value,int32_t argc,JSValueConst * argv)2252 JSValue AppLogPrint(JSContext* ctx, JsLogLevel level, JSValueConst value, int32_t argc, JSValueConst* argv)
2253 {
2254     ACE_SCOPED_TRACE("AppLogPrint(level=%d)", static_cast<int32_t>(level));
2255 
2256     // Should have 1 parameters.
2257     if ((argv == nullptr) || (argc == 0)) {
2258         LOGE("the arg is error");
2259         return JS_EXCEPTION;
2260     }
2261     std::string printLog = ParseLogContent(ctx, argc, argv);
2262     switch (level) {
2263         case JsLogLevel::DEBUG:
2264             APP_LOGD("app Log: %{public}s", printLog.c_str());
2265             break;
2266         case JsLogLevel::INFO:
2267             APP_LOGI("app Log: %{public}s", printLog.c_str());
2268             break;
2269         case JsLogLevel::WARNING:
2270             APP_LOGW("app Log: %{public}s", printLog.c_str());
2271             break;
2272         case JsLogLevel::ERROR:
2273             APP_LOGE("app Log: %{public}s", printLog.c_str());
2274             break;
2275         default:
2276             break;
2277     }
2278 
2279     return JS_NULL;
2280 }
2281 
AppLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2282 JSValue AppLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2283 {
2284     return AppLogPrint(ctx, JsLogLevel::INFO, value, argc, argv);
2285 }
2286 
AppDebugLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2287 JSValue AppDebugLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2288 {
2289     return AppLogPrint(ctx, JsLogLevel::DEBUG, value, argc, argv);
2290 }
2291 
AppInfoLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2292 JSValue AppInfoLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2293 {
2294     return AppLogPrint(ctx, JsLogLevel::INFO, value, argc, argv);
2295 }
2296 
AppWarnLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2297 JSValue AppWarnLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2298 {
2299     return AppLogPrint(ctx, JsLogLevel::WARNING, value, argc, argv);
2300 }
2301 
AppErrorLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2302 JSValue AppErrorLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2303 {
2304     return AppLogPrint(ctx, JsLogLevel::ERROR, value, argc, argv);
2305 }
2306 
GetNodeId(JSContext * ctx,JSValueConst value)2307 int32_t GetNodeId(JSContext* ctx, JSValueConst value)
2308 {
2309     int32_t id = 0;
2310     JSValue nodeId = JS_GetPropertyStr(ctx, value, "__nodeId");
2311     if (JS_IsInteger(nodeId) && (JS_ToInt32(ctx, &id, nodeId)) < 0) {
2312         id = 0;
2313     }
2314     JS_FreeValue(ctx, nodeId);
2315     return id;
2316 }
2317 
JsSetAttribute(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2318 JSValue JsSetAttribute(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2319 {
2320     auto page = GetRunningPage(ctx);
2321     if (page == nullptr) {
2322         return JS_EXCEPTION;
2323     }
2324     if (!JS_IsString(argv[0]) || !JS_IsString(argv[1])) {
2325         LOGE("args is not string ");
2326         return JS_NULL;
2327     }
2328     ScopedString key(ctx, argv[0]);
2329     JSValue attr = JS_NewObject(ctx);
2330     JS_SetPropertyStr(ctx, attr, key.get(), argv[1]);
2331 
2332     int32_t nodeId = GetNodeId(ctx, value);
2333     auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementAttrs>(nodeId);
2334     if (SetDomAttributes(ctx, attr, *command)) {
2335         page->ReserveShowCommand(command);
2336     }
2337     page->PushCommand(command);
2338     return JS_NULL;
2339 }
2340 
JsSetStyle(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2341 JSValue JsSetStyle(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2342 {
2343     auto page = GetRunningPage(ctx);
2344     if (page == nullptr) {
2345     return JS_EXCEPTION;
2346     }
2347     if (!JS_IsString(argv[0]) || !JS_IsString(argv[1])) {
2348         LOGE("args is not string ");
2349         return JS_NULL;
2350     }
2351     ScopedString key(ctx, argv[0]);
2352     JSValue style = JS_NewObject(ctx);
2353     JS_SetPropertyStr(ctx, style, key.get(), argv[1]);
2354     int32_t nodeId = GetNodeId(ctx, value);
2355     auto command = Referenced::MakeRefPtr<JsCommandUpdateDomElementStyles>(nodeId);
2356     SetDomStyle(ctx, style, *command);
2357     page->PushCommand(command);
2358     return JS_NULL;
2359 }
2360 
JsAppendChild(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2361 JSValue JsAppendChild(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2362 {
2363     auto page = GetStagingPage(ctx);
2364     if (page == nullptr) {
2365         LOGE("page is nullptr");
2366         return JS_EXCEPTION;
2367     }
2368 
2369     int32_t id = GetNodeId(ctx, argv[0]);
2370     auto domDocument = page->GetDomDocument();
2371     if (domDocument) {
2372         RefPtr<DOMNode> node = domDocument->GetDOMNodeById(id);
2373         if (node == nullptr) {
2374             LOGE("node is nullptr");
2375         }
2376         int32_t parentNodeId = 0;
2377         JSValue bridgeId = JS_GetPropertyStr(ctx, value, "__nodeId");
2378         if (JS_IsInteger(bridgeId)) {
2379             if ((JS_ToInt32(ctx, &parentNodeId, bridgeId)) < 0) {
2380                 parentNodeId = 0;
2381             }
2382         }
2383         RefPtr<DOMNode> parentNode = domDocument->GetDOMNodeById(parentNodeId);
2384         if (parentNode == nullptr) {
2385             LOGE("node is nullptr");
2386         }
2387         if (node != nullptr && parentNode != nullptr) {
2388             parentNode->RemoveNode(node);
2389         }
2390         auto command = Referenced::MakeRefPtr<JsCommandAppendElement>(node ? node->GetTag() : "", id, parentNodeId);
2391         page->PushCommand(command);
2392         if (!page->CheckPageCreated() && page->GetCommandSize() > FRAGMENT_SIZE) {
2393             page->FlushCommands();
2394         }
2395     }
2396     return JS_NULL;
2397 }
2398 
JsFocus(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2399 JSValue JsFocus(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2400 {
2401     auto page = GetStagingPage(ctx);
2402     if (page == nullptr) {
2403         LOGE("page is nullptr");
2404         return JS_NULL;
2405     }
2406     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
2407     if (instance == nullptr) {
2408         LOGE("JsFocus failed, instance is null.");
2409         return JS_NULL;
2410     }
2411     instance->GetDelegate()->TriggerPageUpdate(page->GetPageId(), true);
2412     return JS_NULL;
2413 }
2414 
JsAnimate(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2415 JSValue JsAnimate(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2416 {
2417     auto page = GetStagingPage(ctx);
2418     if (page == nullptr) {
2419         LOGE("page is nullptr");
2420         return JS_NULL;
2421     }
2422     int32_t nodeId = GetNodeId(ctx, value);
2423     ScopedString args(ctx, argv[0]);
2424     auto resultValue = AnimationBridgeUtils::CreateAnimationContext(ctx, page->GetPageId(), nodeId);
2425     auto animationBridge = AceType::MakeRefPtr<AnimationBridge>(ctx, resultValue, nodeId);
2426     auto task = AceType::MakeRefPtr<AnimationBridgeTaskCreate>(animationBridge, args.get());
2427     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimation>(nodeId, task));
2428     return JS_NULL;
2429 }
2430 
JsGetBoundingClientRect(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2431 JSValue JsGetBoundingClientRect(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2432 {
2433     auto page = GetStagingPage(ctx);
2434     if (page == nullptr) {
2435         LOGE("page is nullptr");
2436         return JS_NULL;
2437     }
2438     int32_t nodeId = GetNodeId(ctx, value);
2439     ComponentApiBridge::JsGetBoundingRect(ctx, nodeId);
2440     return JS_NULL;
2441 }
2442 
JsGetInspector(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2443 JSValue JsGetInspector(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2444 {
2445     auto page = GetStagingPage(ctx);
2446     if (page == nullptr) {
2447         LOGE("page is nullptr");
2448         return JS_NULL;
2449     }
2450     int32_t nodeId = GetNodeId(ctx, value);
2451     ComponentApiBridge::JsGetInspector(ctx, nodeId);
2452     return JS_NULL;
2453 }
2454 
JsCreateElement(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2455 JSValue JsCreateElement(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2456 {
2457     int32_t newNodeId = CreateDomElement(ctx, value, argc, argv);
2458     JSValue node = JS_NewObject(ctx);
2459     JS_SetPropertyStr(ctx, node, "__nodeId",  JS_NewInt32(ctx, newNodeId));
2460     JS_SetPropertyStr(ctx, node, "setAttribute", JS_NewCFunction(ctx, JsSetAttribute, "setAttribute", 2));
2461     JS_SetPropertyStr(ctx, node, "setStyle", JS_NewCFunction(ctx, JsSetStyle, "setStyle", 2));
2462     JS_SetPropertyStr(ctx, node, "addChild", JS_NewCFunction(ctx, JsAppendChild, "addChild", 1));
2463     JS_SetPropertyStr(ctx, node, "focus", JS_NewCFunction(ctx, JsFocus, "focus", 1));
2464     JS_SetPropertyStr(ctx, node, "animate", JS_NewCFunction(ctx, JsAnimate, "animate", 1));
2465     JS_SetPropertyStr(ctx, node, "getBoundingClientRect",
2466         JS_NewCFunction(ctx, JsGetBoundingClientRect, "getBoundingClientRect", 1));
2467     JS_SetPropertyStr(ctx, node, "getInspector", JS_NewCFunction(ctx, JsGetInspector, "getInspector", 1));
2468     return node;
2469 }
2470 
JsLogPrint(JSContext * ctx,JsLogLevel level,JSValueConst value,int32_t argc,JSValueConst * argv)2471 JSValue JsLogPrint(JSContext* ctx, JsLogLevel level, JSValueConst value, int32_t argc, JSValueConst* argv)
2472 {
2473     ACE_SCOPED_TRACE("JsLogPrint(level=%d)", static_cast<int32_t>(level));
2474 
2475     // Should have 1 parameters.
2476     if ((argv == nullptr) || (argc == 0)) {
2477         LOGE("the arg is error");
2478         return JS_EXCEPTION;
2479     }
2480     std::string printLog = ParseLogContent(ctx, argc, argv);
2481     switch (level) {
2482         case JsLogLevel::DEBUG:
2483             LOGD("ace Log: %{public}s", printLog.c_str());
2484             break;
2485         case JsLogLevel::INFO:
2486             LOGI("ace Log: %{public}s", printLog.c_str());
2487             break;
2488         case JsLogLevel::WARNING:
2489             LOGW("ace Log: %{public}s", printLog.c_str());
2490             break;
2491         case JsLogLevel::ERROR:
2492             LOGE("ace Log: %{public}s", printLog.c_str());
2493             break;
2494         default:
2495             break;
2496     }
2497 
2498     return JS_NULL;
2499 }
2500 
JsLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2501 JSValue JsLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2502 {
2503     return JsLogPrint(ctx, JsLogLevel::INFO, value, argc, argv);
2504 }
2505 
JsDebugLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2506 JSValue JsDebugLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2507 {
2508     return JsLogPrint(ctx, JsLogLevel::DEBUG, value, argc, argv);
2509 }
2510 
JsInfoLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2511 JSValue JsInfoLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2512 {
2513     return JsLogPrint(ctx, JsLogLevel::INFO, value, argc, argv);
2514 }
2515 
JsWarnLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2516 JSValue JsWarnLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2517 {
2518     return JsLogPrint(ctx, JsLogLevel::WARNING, value, argc, argv);
2519 }
2520 
JsErrorLogPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2521 JSValue JsErrorLogPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2522 {
2523     return JsLogPrint(ctx, JsLogLevel::ERROR, value, argc, argv);
2524 }
2525 
JsPerfPrint(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2526 JSValue JsPerfPrint(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2527 {
2528     std::string ret = JsApiPerf::GetInstance().PrintToLogs();
2529 
2530     JSValue retString = JS_NewString(ctx, ret.c_str());
2531 
2532     return retString;
2533 }
2534 
AppClearData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2535 JSValue AppClearData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2536 {
2537     if ((argv == nullptr) || (argc == 0)) {
2538         if (dataMap_.size() > 0) {
2539             dataMap_.clear();
2540         }
2541         return JS_TRUE;
2542     }
2543     if (dataMap_.count(ScopedString::Stringify(ctx, argv[0])) == 1) {
2544         dataMap_.erase(ScopedString::Stringify(ctx, argv[0]));
2545         return JS_TRUE;
2546     }
2547     return JS_FALSE;
2548 }
2549 
AppSetData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2550 JSValue AppSetData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2551 {
2552     if ((argv == nullptr) || (argc != 2)) {
2553         return JS_EXCEPTION;
2554     }
2555     std::string key = ScopedString::Stringify(ctx, argv[0]);
2556     std::string mapValue = ScopedString::Stringify(ctx, argv[1]);
2557     dataMap_[key] = mapValue;
2558     return JS_TRUE;
2559 }
2560 
AppGetData(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2561 JSValue AppGetData(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2562 {
2563     if ((argv == nullptr) || (argc == 0)) {
2564         return JS_NULL;
2565     }
2566     std::string key = ScopedString::Stringify(ctx, argv[0]);
2567     if (dataMap_.count(key) == 1) {
2568         std::string mapValue = dataMap_[key];
2569         return QJSUtils::ParseJSON(ctx, mapValue.c_str(), mapValue.length());
2570     }
2571     return JS_NULL;
2572 }
2573 
AppSetDataImage(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2574 JSValue AppSetDataImage(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2575 {
2576     auto page = GetStagingPage(ctx);
2577     if (page == nullptr) {
2578         LOGE("page is nullptr");
2579         return JS_EXCEPTION;
2580     }
2581     if ((argv == nullptr) || (argc != 3)) {
2582         return JS_EXCEPTION;
2583     }
2584     return JS_NULL;
2585 }
2586 
JsPerfSleep(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2587 JSValue JsPerfSleep(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2588 {
2589     int32_t valInt = 0;
2590     JS_ToInt32(ctx, &valInt, argv[0]);
2591 
2592     usleep(valInt);
2593 
2594     return JS_NULL;
2595 }
2596 
JsPerfBegin(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2597 JSValue JsPerfBegin(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2598 {
2599     int64_t currentTime = GetMicroTickCount();
2600     ScopedString functionName(ctx, argv[0]);
2601 
2602     JsApiPerf::GetInstance().InsertJsBeginLog(functionName.get(), currentTime);
2603 
2604     return JS_NULL;
2605 }
2606 
JsPerfEnd(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2607 JSValue JsPerfEnd(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2608 {
2609     int64_t currentTime = GetMicroTickCount();
2610     ScopedString functionName(ctx, argv[0]);
2611 
2612     JsApiPerf::GetInstance().InsertJsEndLog(functionName.get(), currentTime);
2613 
2614     return JS_NULL;
2615 }
2616 
JSHiViewReport(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2617 JSValue JSHiViewReport(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2618 {
2619     // Should have 2 parameters.
2620     if ((argv == nullptr) || (argc != 2)) {
2621         LOGE("the arg is error %{public}d", argc);
2622         return JS_EXCEPTION;
2623     }
2624     if (JS_IsInteger(argv[0]) && JS_IsString(argv[1])) {
2625         ScopedString eventId(ctx, argv[0]);
2626         ScopedString eventJsonStr(ctx, argv[1]);
2627         std::string jsonStr = eventJsonStr.get();
2628         EventReport::JsEventReport(StringToInt(eventId.get()), jsonStr);
2629         LOGD("JsEventReport success");
2630         return JS_NULL;
2631     } else {
2632         LOGE("parameter type error ");
2633         return JS_EXCEPTION;
2634     }
2635 }
2636 
JsPluralRulesFormat(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2637 JSValue JsPluralRulesFormat(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2638 {
2639     // Should have one parameters.
2640     if ((argv == nullptr) || (argc != 1)) {
2641         LOGE("the arg is error %{public}d", argc);
2642         return JS_NULL;
2643     }
2644     if (JS_IsInteger(argv[0])) {
2645         ScopedString choice(ctx, argv[0]);
2646         JSValue result =
2647             JS_NewString(ctx, Localization::GetInstance()->PluralRulesFormat(StringToDouble(choice.get())).c_str());
2648         return result;
2649     } else {
2650         LOGE("parameter type error ");
2651         return JS_NULL;
2652     }
2653 }
2654 
2655 // Follow definition in quickjs.
2656 #define JS_CFUNC_DEF_CPP(name, length, func)                            \
2657     {                                                                   \
2658         name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, \
2659         {                                                               \
2660             {                                                           \
2661                 length, JS_CFUNC_generic,                               \
2662                 {                                                       \
2663                     func                                                \
2664                 }                                                       \
2665             }                                                           \
2666         }                                                               \
2667     }
2668 
2669 const JSCFunctionListEntry JS_ACE_FUNCS[] = {
2670     JS_CFUNC_DEF_CPP("domCreateBody", 5, JsDomCreateBody),
2671     JS_CFUNC_DEF_CPP("domAddElement", 9, JsDomAddElement),
2672     JS_CFUNC_DEF_CPP("updateElementAttrs", 3, JsUpdateElementAttrs),
2673     JS_CFUNC_DEF_CPP("updateElementStyles", 3, JsUpdateElementStyles),
2674     JS_CFUNC_DEF_CPP("onCreateFinish", 0, JsOnCreateFinish),
2675     JS_CFUNC_DEF_CPP("onUpdateFinish", 0, JsOnUpdateFinish),
2676     JS_CFUNC_DEF_CPP("removeElement", 2, JsRemoveElement),
2677     JS_CFUNC_DEF_CPP("callNative", 1, JsCallNative),
2678     JS_CFUNC_DEF_CPP("callComponent", 3, JsCallComponent),
2679 #if defined(ENABLE_JS_DEBUG) || defined(ENABLE_JS_DEBUG_PREVIEW)
2680     JS_CFUNC_DEF_CPP("compileAndRunBundle", 4, JsCompileAndRunBundle),
2681 #endif
2682 };
2683 
JsAceInit(JSContext * ctx,JSModuleDef * moduleDef)2684 int32_t JsAceInit(JSContext* ctx, JSModuleDef* moduleDef)
2685 {
2686     return JS_SetModuleExportList(ctx, moduleDef, JS_ACE_FUNCS, countof(JS_ACE_FUNCS));
2687 }
2688 
InitAceModules(JSContext * ctx)2689 JSModuleDef* InitAceModules(JSContext* ctx)
2690 {
2691     LOGD("QjsEngine: InitAceModules");
2692     JSModuleDef* jsModule = JS_NewCModule(ctx, "ace", JsAceInit);
2693     if (jsModule == nullptr) {
2694         return nullptr;
2695     }
2696     JS_AddModuleExportList(ctx, jsModule, JS_ACE_FUNCS, countof(JS_ACE_FUNCS));
2697     return jsModule;
2698 }
2699 
JsCallNativeHandler(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)2700 JSValue JsCallNativeHandler(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
2701 {
2702     if (argc != 2 || argv == nullptr || !JS_IsString(argv[0]) || !JS_IsString(argv[1])) {
2703         LOGE("JsCallNativeHandler: invalid parameters");
2704         return JS_NULL;
2705     }
2706 
2707     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
2708     if (instance == nullptr) {
2709         return JS_NULL;
2710     }
2711 
2712     ScopedString event(ctx, argv[0]);
2713     ScopedString params(ctx, argv[1]);
2714     instance->GetDelegate()->CallNativeHandler(event.str(), params.str());
2715     return JS_NULL;
2716 }
2717 
InitJsConsoleObject(JSContext * ctx,const JSValue & globalObj)2718 void InitJsConsoleObject(JSContext* ctx, const JSValue& globalObj)
2719 {
2720     JSValue console, aceConsole;
2721     // app log method
2722     console = JS_NewObject(ctx);
2723     JS_SetPropertyStr(ctx, console, "log", JS_NewCFunction(ctx, AppLogPrint, "log", 1));
2724     JS_SetPropertyStr(ctx, console, "debug", JS_NewCFunction(ctx, AppDebugLogPrint, "debug", 1));
2725     JS_SetPropertyStr(ctx, console, "info", JS_NewCFunction(ctx, AppInfoLogPrint, "info", 1));
2726     JS_SetPropertyStr(ctx, console, "warn", JS_NewCFunction(ctx, AppWarnLogPrint, "warn", 1));
2727     JS_SetPropertyStr(ctx, console, "error", JS_NewCFunction(ctx, AppErrorLogPrint, "error", 1));
2728     JS_SetPropertyStr(ctx, globalObj, "console", console);
2729 
2730     // js framework log method
2731     aceConsole = JS_NewObject(ctx);
2732     JS_SetPropertyStr(ctx, aceConsole, "log", JS_NewCFunction(ctx, JsLogPrint, "log", 1));
2733     JS_SetPropertyStr(ctx, aceConsole, "debug", JS_NewCFunction(ctx, JsDebugLogPrint, "debug", 1));
2734     JS_SetPropertyStr(ctx, aceConsole, "info", JS_NewCFunction(ctx, JsInfoLogPrint, "info", 1));
2735     JS_SetPropertyStr(ctx, aceConsole, "warn", JS_NewCFunction(ctx, JsWarnLogPrint, "warn", 1));
2736     JS_SetPropertyStr(ctx, aceConsole, "error", JS_NewCFunction(ctx, JsErrorLogPrint, "error", 1));
2737     JS_SetPropertyStr(ctx, globalObj, "aceConsole", aceConsole);
2738     JS_SetPropertyStr(ctx, globalObj, "callNativeHandler",
2739         JS_NewCFunction(ctx, JsCallNativeHandler, "callNativeHandler", 1));
2740 }
2741 
InitJsDocumentObject(JSContext * ctx,const JSValue & globalObj)2742 void InitJsDocumentObject(JSContext* ctx, const JSValue& globalObj)
2743 {
2744     JSValue dom = JS_NewObject(ctx);
2745     JS_SetPropertyStr(ctx, dom, "createElement", JS_NewCFunction(ctx, JsCreateElement, "createElement", 1));
2746     JS_SetPropertyStr(ctx, globalObj, "dom", dom);
2747 }
2748 
InitJsContext(JSContext * ctx,size_t maxStackSize,int32_t instanceId,const QjsEngineInstance * qjsEngineInstance,const std::unordered_map<std::string,void * > & extraNativeObject)2749 bool InitJsContext(JSContext* ctx, size_t maxStackSize, int32_t instanceId, const QjsEngineInstance* qjsEngineInstance,
2750     const std::unordered_map<std::string, void*>& extraNativeObject)
2751 {
2752     LOGI("QjsEngine: InitJsContext");
2753     if (ctx == nullptr) {
2754         LOGE("Qjs cannot allocate JS context");
2755         EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
2756         return false;
2757     }
2758 
2759     // Note: default 256KB is not enough
2760     JS_SetMaxStackSize(ctx, maxStackSize);
2761 
2762     // Inject ace native functions module
2763     InitAceModules(ctx);
2764 
2765     JSValue globalObj, perfUtil;
2766     globalObj = JS_GetGlobalObject(ctx);
2767     perfUtil = JS_NewObject(ctx);
2768 
2769     InitJsConsoleObject(ctx, globalObj);
2770     InitJsDocumentObject(ctx, globalObj);
2771 
2772     JS_SetPropertyStr(ctx, perfUtil, "printlog", JS_NewCFunction(ctx, JsPerfPrint, "printlog", 0));
2773     JS_SetPropertyStr(ctx, perfUtil, "sleep", JS_NewCFunction(ctx, JsPerfSleep, "sleep", 1));
2774     JS_SetPropertyStr(ctx, perfUtil, "begin", JS_NewCFunction(ctx, JsPerfBegin, "begin", 1));
2775     JS_SetPropertyStr(ctx, perfUtil, "end", JS_NewCFunction(ctx, JsPerfEnd, "end", 1));
2776     JS_SetPropertyStr(ctx, globalObj, "perfutil", perfUtil);
2777 
2778 #if !defined(PREVIEW)
2779     for (const auto& [key, value] : extraNativeObject) {
2780         auto nativeObjectInfo = std::make_unique<NativeObjectInfo>();
2781         nativeObjectInfo->nativeObject = value;
2782         JSValue abilityValue = JS_NewExternal(ctx, nativeObjectInfo.release(),
2783             [](JSContext* ctx, void *data, void *hint) {
2784                 std::unique_ptr<NativeObjectInfo> info(static_cast<NativeObjectInfo*>(data));
2785             }, nullptr);
2786         JS_SetPropertyStr(ctx, globalObj, key.c_str(), abilityValue);
2787     }
2788 #endif
2789 
2790     JSValue hiView;
2791     hiView = JS_NewObject(ctx);
2792     JS_SetPropertyStr(ctx, hiView, "report", JS_NewCFunction(ctx, JSHiViewReport, "report", 2));
2793     JS_SetPropertyStr(ctx, globalObj, "hiView", hiView);
2794 
2795     JSValue i18nPluralRules;
2796     i18nPluralRules = JS_NewObject(ctx);
2797     JS_SetPropertyStr(ctx, i18nPluralRules, "select", JS_NewCFunction(ctx, JsPluralRulesFormat, "select", 1));
2798     JS_SetPropertyStr(ctx, globalObj, "i18nPluralRules", i18nPluralRules);
2799 
2800     const char* str = "import * as ace from 'ace';\n"
2801                       "var global = globalThis;\n"
2802                       "global.ace = ace;\n"
2803 #if defined(ENABLE_JS_DEBUG) || defined(ENABLE_JS_DEBUG_PREVIEW)
2804                       "global.compileAndRunBundle = ace.compileAndRunBundle;\n"
2805 #endif
2806                       "global.callNative = ace.callNative;\n";
2807 
2808     if (JS_CALL_FAIL == CallEvalBuf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE, instanceId)) {
2809         LOGW("Qjs created JS context but failed to init Ace modules!");
2810     }
2811 
2812     JS_FreeValue(ctx, globalObj);
2813     return true;
2814 }
2815 
LoadJsFramework(JSContext * ctx,const uint8_t buf[],const uint32_t bufSize,int32_t instanceId)2816 JSValue LoadJsFramework(JSContext* ctx, const uint8_t buf[], const uint32_t bufSize, int32_t instanceId)
2817 {
2818     ACE_SCOPED_TRACE("LoadJsFramework");
2819 
2820     LOGI("Qjs loading JS framework");
2821     JSValue ret = CallReadObject(ctx, buf, bufSize, true, instanceId);
2822     if (JS_IsException(ret)) {
2823         LOGD("Qjs loading JSFramework failed!");
2824         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::LOAD_JS_FRAMEWORK_ERROR, instanceId);
2825     }
2826     js_std_loop(ctx);
2827     return ret;
2828 }
2829 
2830 } // namespace
2831 
2832 // -----------------------
2833 // Start QjsEngineInstance
2834 // -----------------------
FlushCommandBuffer(void * context,const std::string & command)2835 void QjsEngineInstance::FlushCommandBuffer(void* context, const std::string& command)
2836 {
2837     LOGI("flush command buffer");
2838     auto ctx = static_cast<JSContext*>(context);
2839     int32_t result = CallEvalBuf(ctx, command.c_str(), command.size(), "<input>", JS_EVAL_TYPE_GLOBAL, instanceId_);
2840     if (JS_CALL_FAIL == result) {
2841         LOGE("failed to flush command buffer");
2842     }
2843 }
InitJsEnv(JSRuntime * runtime,JSContext * context,const std::unordered_map<std::string,void * > & extraNativeObject)2844 bool QjsEngineInstance::InitJsEnv(
2845     JSRuntime* runtime, JSContext* context, const std::unordered_map<std::string, void*>& extraNativeObject)
2846 {
2847     LOGI("InitJsEnv");
2848     if (runtime == nullptr) {
2849         runtime = JS_NewRuntime();
2850     }
2851     if (runtime_ != nullptr) {
2852         JS_FreeRuntime(runtime_);
2853     }
2854     runtime_ = runtime;
2855     if (runtime_ == nullptr) {
2856         LOGE("Qjs cannot allocate JS runtime");
2857         EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
2858         return false;
2859     }
2860 
2861     if (context == nullptr) {
2862         context = JS_NewContext(runtime_);
2863     }
2864     if (context_ != nullptr) {
2865         JS_FreeContext(context_);
2866     }
2867     context_ = context;
2868     if (!InitJsContext(context_, MAX_STACK_SIZE, instanceId_, this, extraNativeObject)) {
2869         LOGE("Qjs cannot allocate JS context");
2870         EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
2871         JS_FreeRuntime(runtime_);
2872         return false;
2873     }
2874 
2875     auto groupJsBridge = AceType::DynamicCast<QuickJsGroupJsBridge>(frontendDelegate_->GetGroupJsBridge());
2876     if (!groupJsBridge || JS_CALL_FAIL == groupJsBridge->InitializeGroupJsBridge(context_)) {
2877         LOGE("Qjs Initialize GroupJsBridge failed!");
2878         EventReport::SendJsException(JsExcepType::JS_ENGINE_INIT_ERR);
2879         return false;
2880     }
2881 
2882     JSValue retVal = LoadJsFramework(GetQjsContext(), js_framework, js_framework_size, instanceId_);
2883     bool result = JS_IsException(retVal) ? false : true;
2884     if (context) {
2885         JS_FreeValue(context, retVal);
2886     }
2887 
2888     return result;
2889 }
2890 
FreeGroupJsBridge()2891 void QjsEngineInstance::FreeGroupJsBridge()
2892 {
2893     // free JSValue reference of channel bridge and animation bridge
2894     if (!frontendDelegate_) {
2895         LOGE("frontend delegate is null.");
2896         return;
2897     }
2898 
2899     auto groupJsBridge = AceType::DynamicCast<QuickJsGroupJsBridge>(frontendDelegate_->GetGroupJsBridge());
2900     if (!groupJsBridge) {
2901         LOGE("group js bridge is null.");
2902         return;
2903     }
2904     groupJsBridge->Uninitialize();
2905 }
2906 
~QjsEngineInstance()2907 QjsEngineInstance::~QjsEngineInstance()
2908 {
2909     if (runningPage_) {
2910         runningPage_->OnJsEngineDestroy();
2911     }
2912 
2913     if (stagingPage_) {
2914         stagingPage_->OnJsEngineDestroy();
2915     }
2916     FreeGroupJsBridge();
2917 
2918     if (context_) {
2919         JS_FreeContext(context_);
2920     }
2921     if (runtime_) {
2922         JS_FreeRuntime(runtime_);
2923     }
2924 }
2925 
FireJsEvent(const std::string & param)2926 JSValue QjsEngineInstance::FireJsEvent(const std::string& param)
2927 {
2928     LOGI("FireJsEvent");
2929     JSContext* ctx = GetQjsContext();
2930     ACE_DCHECK(ctx);
2931     QJSHandleScope handleScope(ctx);
2932     JSValue globalObj = JS_GetGlobalObject(ctx);
2933     JSValue callJsFunc = QJSUtils::GetPropertyStr(ctx, globalObj, "callJS");
2934     if (!JS_IsFunction(ctx, callJsFunc)) {
2935         LOGE("cannot find 'callJS' function from global object, this should not happen!");
2936         JS_FreeValue(ctx, globalObj);
2937         return JS_UNDEFINED;
2938     }
2939 
2940     if (!runningPage_) {
2941         LOGE("runningPage_ is null!");
2942         JS_FreeValue(ctx, globalObj);
2943         return JS_UNDEFINED;
2944     }
2945     JSValue jsValue = QJSUtils::ParseJSON(ctx, param.c_str(), param.size(), nullptr);
2946     if (JS_IsArray(ctx, jsValue)) {
2947         JSValue itemVal = JS_GetPropertyUint32(ctx, jsValue, 0);
2948         if (JS_IsObject(itemVal)) {
2949             JSValue args = JS_GetPropertyStr(ctx, itemVal, "args");
2950             if (JS_IsArray(ctx, args)) {
2951                 JSValue stdDrag = JS_GetPropertyUint32(ctx, args, 1);
2952                 if (IsDragEvent(ScopedString::Stringify(ctx, stdDrag))) {
2953                     JSValue arg2 = JS_GetPropertyUint32(ctx, args, 2);
2954                     if (JS_IsObject(arg2)) {
2955                         JSValue arg1 = JS_NewObject(ctx);
2956                         JS_SetPropertyStr(ctx, arg1, "clearData", JS_NewCFunction(ctx, AppClearData, "clearData", 1));
2957                         JS_SetPropertyStr(ctx, arg1, "getData", JS_NewCFunction(ctx, AppGetData, "getData", 1));
2958                         JS_SetPropertyStr(ctx, arg1, "setData", JS_NewCFunction(ctx, AppSetData, "setData", 2));
2959                         JS_SetPropertyStr(
2960                             ctx, arg1, "setDragImage", JS_NewCFunction(ctx, AppSetDataImage, "setDragImage", 3));
2961                         JS_SetPropertyStr(ctx, arg2, "dataTransfer", arg1);
2962                         JS_FreeValue(ctx, arg1);
2963                     }
2964                     JS_FreeValue(ctx, arg2);
2965                 }
2966                 JS_FreeValue(ctx, stdDrag);
2967             }
2968             JS_FreeValue(ctx, args);
2969         }
2970         JS_FreeValue(ctx, itemVal);
2971     }
2972     JSValueConst argv[] = {
2973         QJSUtils::NewString(ctx, std::to_string(runningPage_->GetPageId()).c_str()),
2974         jsValue,
2975     };
2976 
2977     JSValue retVal = JS_Call(ctx, callJsFunc, globalObj, countof(argv), argv);
2978 
2979     js_std_loop(ctx);
2980     JS_FreeValue(ctx, globalObj);
2981 
2982     // It is up to the caller to check this value. No exception checks here.
2983     return retVal;
2984 }
2985 
IsDragEvent(const std::string & param)2986 bool QjsEngineInstance::IsDragEvent(const std::string& param)
2987 {
2988     std::string::size_type idx = param.find("drag");
2989     return !(idx == std::string::npos);
2990 }
2991 
CallJs(const std::string & callbackId,const std::string & args,bool keepAlive,bool isGlobal)2992 void QjsEngineInstance::CallJs(const std::string& callbackId, const std::string& args, bool keepAlive, bool isGlobal)
2993 {
2994     ACE_SCOPED_TRACE("QjsEngineInstance::CallJS");
2995 
2996     std::string keepAliveStr = keepAlive ? "true" : "false";
2997     std::string callBuff = std::string("[{\"args\": [\"")
2998                                .append(callbackId)
2999                                .append("\",")
3000                                .append(args)
3001                                .append(",")
3002                                .append(keepAliveStr)
3003                                .append("], \"method\":\"callback\"}]");
3004     LOGD("CallJs string: %{private}s", callBuff.c_str());
3005 
3006     JSContext* ctx = GetQjsContext();
3007     QJSHandleScope handleScope(ctx);
3008     JSValue globalObj = JS_GetGlobalObject(ctx);
3009     JSValue callJsFunc = QJSUtils::GetPropertyStr(ctx, globalObj, "callJS");
3010     if (!JS_IsFunction(ctx, callJsFunc)) {
3011         LOGE("cannot find 'callJS' function from global object, this should not happen!");
3012         JS_FreeValue(ctx, globalObj);
3013         return;
3014     }
3015 
3016     int32_t instanceId = isGlobal ? DEFAULT_APP_ID : stagingPage_->GetPageId();
3017     JSValueConst argv[] = {
3018         QJSUtils::NewString(ctx, std::to_string(instanceId).c_str()),
3019         QJSUtils::ParseJSON(ctx, callBuff.c_str(), callBuff.size(), nullptr),
3020     };
3021     JSValue retVal = QJSUtils::Call(ctx, callJsFunc, globalObj, countof(argv), argv);
3022 
3023     if (JS_IsException(retVal)) {
3024         LOGE("JS framework execute callback failed");
3025         JS_FreeValue(ctx, globalObj);
3026         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::JS_CALLBACK_ERROR, instanceId_, stagingPage_->GetUrl().c_str(),
3027             stagingPage_);
3028         return;
3029     }
3030     js_std_loop(ctx);
3031     JS_FreeValue(ctx, globalObj);
3032 }
3033 
CallAnimationStartJs(JSValue animationContext)3034 void QjsEngineInstance::CallAnimationStartJs(JSValue animationContext)
3035 {
3036     JSContext* ctx = GetQjsContext();
3037     QJSHandleScope handleScope(ctx);
3038     auto proto = QJSUtils::GetPropertyStr(ctx, animationContext, "onstart");
3039     if (!JS_IsFunction(ctx, proto)) {
3040         LOGD("cannot find 'CallAnimationStartJs' function from global object, this should not happen!");
3041         return;
3042     }
3043     LOGD("animation onstart event call");
3044     JSValue retVal = QJSUtils::Call(ctx, proto, animationContext, 0, {});
3045     JSValue globalObj = JS_GetGlobalObject(ctx);
3046 
3047     if (JS_IsException(retVal)) {
3048         LOGE("JS framework execute callAnimationStart failed");
3049         JS_FreeValue(ctx, globalObj);
3050         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::JS_CALLBACK_ERROR, instanceId_, stagingPage_->GetUrl().c_str(),
3051             stagingPage_);
3052         return;
3053     }
3054     js_std_loop(ctx);
3055 }
3056 
CallAnimationFinishJs(JSValue animationContext)3057 void QjsEngineInstance::CallAnimationFinishJs(JSValue animationContext)
3058 {
3059     JSContext* ctx = GetQjsContext();
3060     QJSHandleScope handleScope(ctx);
3061     auto proto = QJSUtils::GetPropertyStr(ctx, animationContext, "onfinish");
3062     if (!JS_IsFunction(ctx, proto)) {
3063         LOGD("cannot find 'CallAnimationFinishJs' function from global object, this should not happen!");
3064         return;
3065     }
3066     LOGD("animation onfinish event call");
3067     JSValue retVal = QJSUtils::Call(ctx, proto, animationContext, 0, {});
3068     JSValue globalObj = JS_GetGlobalObject(ctx);
3069 
3070     if (JS_IsException(retVal)) {
3071         LOGE("JS framework execute callAnimationFinish failed");
3072         JS_FreeValue(ctx, globalObj);
3073         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::JS_CALLBACK_ERROR, instanceId_, stagingPage_->GetUrl().c_str(),
3074             stagingPage_);
3075         return;
3076     }
3077     js_std_loop(ctx);
3078 }
3079 
CallAnimationCancelJs(JSValue animationContext)3080 void QjsEngineInstance::CallAnimationCancelJs(JSValue animationContext)
3081 {
3082     JSContext* ctx = GetQjsContext();
3083     QJSHandleScope handleScope(ctx);
3084     auto proto = QJSUtils::GetPropertyStr(ctx, animationContext, "oncancel");
3085     if (!JS_IsFunction(ctx, proto)) {
3086         return;
3087     }
3088 
3089     LOGD("animation oncancel event call");
3090     JSValue retVal = QJSUtils::Call(ctx, proto, animationContext, 0, {});
3091     JSValue globalObj = JS_GetGlobalObject(ctx);
3092 
3093     if (JS_IsException(retVal)) {
3094         LOGE("JS framework execute callAnimationCancel failed");
3095         JS_FreeValue(ctx, globalObj);
3096         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::JS_CALLBACK_ERROR, instanceId_, stagingPage_->GetUrl().c_str(),
3097             stagingPage_);
3098         return;
3099     }
3100     js_std_loop(ctx);
3101 }
3102 
CallAnimationRepeatJs(JSValue animationContext)3103 void QjsEngineInstance::CallAnimationRepeatJs(JSValue animationContext)
3104 {
3105     JSContext* ctx = GetQjsContext();
3106     QJSHandleScope handleScope(ctx);
3107     auto proto = QJSUtils::GetPropertyStr(ctx, animationContext, "onrepeat");
3108     if (!JS_IsFunction(ctx, proto)) {
3109         return;
3110     }
3111 
3112     LOGD("animation onrepeat event call");
3113     JSValue retVal = QJSUtils::Call(ctx, proto, animationContext, 0, {});
3114     JSValue globalObj = JS_GetGlobalObject(ctx);
3115 
3116     if (JS_IsException(retVal)) {
3117         LOGE("JS framework execute callAnimationRepeatJs failed");
3118         JS_FreeValue(ctx, globalObj);
3119         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::JS_CALLBACK_ERROR, instanceId_, stagingPage_->GetUrl().c_str(),
3120             stagingPage_);
3121         return;
3122     }
3123     js_std_loop(ctx);
3124 }
3125 
CallAnimationFrameJs(JSValue animationContext,const char * str)3126 void QjsEngineInstance::CallAnimationFrameJs(JSValue animationContext, const char* str)
3127 {
3128     JSContext* ctx = GetQjsContext();
3129     QJSHandleScope handleScope(ctx);
3130     auto proto = QJSUtils::GetPropertyStr(ctx, animationContext, "onframe");
3131     if (!JS_IsFunction(ctx, proto)) {
3132         return;
3133     }
3134 
3135     LOGD("animation onframe event call");
3136     JSValue value = QJSUtils::NewString(ctx, str);
3137     JSValueConst argv[] = { value };
3138     QJSUtils::Call(ctx, proto, animationContext, 1, argv);
3139     js_std_loop(ctx);
3140 }
3141 
3142 // -----------------------
3143 // Start QjsEngine
3144 // -----------------------
Initialize(const RefPtr<FrontendDelegate> & delegate)3145 bool QjsEngine::Initialize(const RefPtr<FrontendDelegate>& delegate)
3146 {
3147     ACE_SCOPED_TRACE("QjsEngine::Initialize");
3148     LOGI("Initialize");
3149 
3150     JSRuntime* runtime = nullptr;
3151     JSContext* context = nullptr;
3152 
3153     // put JS_NewContext as early as possible to make stack_top in context
3154     // closer to the top stack frame pointer of JS thread.
3155     runtime = JS_NewRuntime();
3156     if (runtime != nullptr) {
3157         context = JS_NewContext(runtime);
3158     }
3159 
3160     LOGD("QjsEngine initialize");
3161 
3162 #ifdef ENABLE_JS_DEBUG
3163     LOGI("QjsEngine debug mode");
3164     std::string instanceName = GetInstanceName();
3165     if (instanceName.empty()) {
3166         LOGE("GetInstanceName fail, %s", instanceName.c_str());
3167         return false;
3168     }
3169     constexpr int32_t COMPONENT_NAME_MAX_LEN = 100;
3170     char componentName[COMPONENT_NAME_MAX_LEN];
3171     if (!DBG_CopyComponentNameFromAce(instanceName.c_str(), componentName, COMPONENT_NAME_MAX_LEN)) {
3172         LOGE("GetInstanceName strcpy_s fail");
3173         return false;
3174     }
3175     DBG_SetComponentNameAndInstanceId(componentName, strlen(componentName), instanceId_);
3176     DBG_SetNeedDebugBreakPoint(NeedDebugBreakPoint());
3177 #endif
3178     ACE_DCHECK(delegate);
3179 
3180     engineInstance_ = AceType::MakeRefPtr<QjsEngineInstance>(delegate, instanceId_);
3181     nativeEngine_ = new QuickJSNativeEngine(runtime, context, static_cast<void*>(this));
3182     engineInstance_->SetQuickJSNativeEngine(static_cast<QuickJSNativeEngine*>(nativeEngine_));
3183     bool ret = engineInstance_->InitJsEnv(runtime, context, GetExtraNativeObject());
3184 
3185     SetPostTask(nativeEngine_);
3186 #if !defined(PREVIEW)
3187     nativeEngine_->CheckUVLoop();
3188 #endif
3189     RegisterWorker();
3190     if (delegate && delegate->GetAssetManager()) {
3191         std::vector<std::string> packagePath = delegate->GetAssetManager()->GetLibPath();
3192         if (!packagePath.empty()) {
3193             auto qjsEngine = static_cast<QuickJSNativeEngine*>(nativeEngine_);
3194             qjsEngine->SetPackagePath(packagePath);
3195         }
3196     }
3197 
3198     return ret;
3199 }
3200 
SetPostTask(NativeEngine * nativeEngine)3201 void QjsEngine::SetPostTask(NativeEngine* nativeEngine)
3202 {
3203     LOGI("SetPostTask");
3204     auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
3205     auto&& postTask = [weakDelegate, weakEngine = AceType::WeakClaim(this), id = instanceId_](bool needSync) {
3206         auto delegate = weakDelegate.Upgrade();
3207         if (delegate == nullptr) {
3208             LOGE("delegate is nullptr");
3209             return;
3210         }
3211 
3212         delegate->PostJsTask([weakEngine, needSync, id]() {
3213             ContainerScope scope(id);
3214             auto jsEngine = weakEngine.Upgrade();
3215             if (jsEngine == nullptr) {
3216                 LOGW("jsEngine is nullptr");
3217                 return;
3218             }
3219             auto nativeEngine = jsEngine->GetNativeEngine();
3220             if (nativeEngine == nullptr) {
3221                 return;
3222             }
3223             nativeEngine->Loop(LOOP_NOWAIT, needSync);
3224         });
3225     };
3226     nativeEngine_->SetPostTask(postTask);
3227 }
3228 
RegisterInitWorkerFunc()3229 void QjsEngine::RegisterInitWorkerFunc()
3230 {
3231     auto&& initWorkerFunc = [](NativeEngine* nativeEngine) {
3232         LOGI("WorkerCore RegisterInitWorkerFunc called");
3233         if (nativeEngine == nullptr) {
3234             LOGE("nativeEngine is nullptr");
3235             return;
3236         }
3237         auto qjsNativeEngine = static_cast<QuickJSNativeEngine*>(nativeEngine);
3238         if (qjsNativeEngine == nullptr) {
3239             LOGE("qjsNativeEngine is nullptr");
3240             return;
3241         }
3242 
3243         JSContext* ctx = qjsNativeEngine->GetContext();
3244         if (ctx == nullptr) {
3245             LOGE("ctx is nullptr");
3246             return;
3247         }
3248 
3249         // Create a stack-allocated handle scope.
3250         QJSHandleScope handleScope(ctx);
3251 
3252         // Note: default 256KB is not enough
3253         JS_SetMaxStackSize(ctx, MAX_STACK_SIZE);
3254 
3255         JSValue globalObj = JS_GetGlobalObject(ctx);
3256         InitJsConsoleObject(ctx, globalObj);
3257         JS_FreeValue(ctx, globalObj);
3258     };
3259     nativeEngine_->SetInitWorkerFunc(initWorkerFunc);
3260 }
3261 
RegisterAssetFunc()3262 void QjsEngine::RegisterAssetFunc()
3263 {
3264     auto weakDelegate = AceType::WeakClaim(AceType::RawPtr(engineInstance_->GetDelegate()));
3265     auto&& assetFunc = [weakDelegate](const std::string& uri, std::vector<uint8_t>& content, std::string& ami) {
3266         LOGI("WorkerCore RegisterAssetFunc called");
3267         auto delegate = weakDelegate.Upgrade();
3268         if (delegate == nullptr) {
3269             LOGE("delegate is nullptr");
3270             return;
3271         }
3272         delegate->GetResourceData(uri, content, ami);
3273     };
3274     nativeEngine_->SetGetAssetFunc(assetFunc);
3275 }
3276 
RegisterWorker()3277 void QjsEngine::RegisterWorker()
3278 {
3279     RegisterInitWorkerFunc();
3280     RegisterAssetFunc();
3281 }
3282 
~QjsEngine()3283 QjsEngine::~QjsEngine()
3284 {
3285     LOG_DESTROY();
3286     if (nativeEngine_ != nullptr) {
3287 #if !defined(PREVIEW)
3288         nativeEngine_->CancelCheckUVLoop();
3289 #endif
3290         nativeEngine_->DeleteEngine();
3291         delete nativeEngine_;
3292     }
3293     if (engineInstance_ && engineInstance_->GetQjsRuntime()) {
3294         JS_RunGC(engineInstance_->GetQjsRuntime());
3295         engineInstance_->SetNativeEngine(nullptr);
3296     }
3297 }
3298 
GetLoadOptions(std::string & optionStr,bool isMainPage,const RefPtr<JsAcePage> & page)3299 void QjsEngine::GetLoadOptions(std::string& optionStr, bool isMainPage, const RefPtr<JsAcePage>& page)
3300 {
3301     auto mediaQuery = engineInstance_->GetDelegate()->GetMediaQueryInfoInstance();
3302     auto renderOption = MediaQueryInfo::GetMediaQueryJsonInfo();
3303     if (mediaQuery) {
3304         renderOption->Put("isInit", mediaQuery->GetIsInit());
3305         renderOption->Put("bundleUrl", page->GetUrl().c_str());
3306     }
3307     renderOption->Put("appInstanceId", "10002");
3308     renderOption->Put("pcPreview", PC_PREVIEW);
3309     renderOption->Put("packageName", engineInstance_->GetDelegate()->GetAppID().c_str());
3310 
3311     // get resourceConfig
3312     engineInstance_->GetDelegate()->GetResourceConfiguration(renderOption);
3313 
3314     // get i18n message
3315     std::string language = AceApplicationInfo::GetInstance().GetLanguage();
3316     std::string region = AceApplicationInfo::GetInstance().GetCountryOrRegion();
3317     engineInstance_->GetDelegate()->GetI18nData(renderOption);
3318     std::string local = language + "_" + region;
3319     renderOption->Put("language", local.c_str());
3320 
3321     if (isMainPage) {
3322         JSContext* ctx = engineInstance_->GetQjsContext();
3323         std::string commonsJsContent;
3324         if (engineInstance_->GetDelegate()->GetAssetContent("commons.js", commonsJsContent)) {
3325             auto commonsJsResult = CallEvalBuf(ctx, commonsJsContent.c_str(), commonsJsContent.size(),
3326                 "commons.js", JS_EVAL_TYPE_MODULE, instanceId_);
3327             if (commonsJsResult == JS_CALL_FAIL) {
3328                 LOGE("fail to execute load commonsjs script");
3329             }
3330         }
3331         std::string vendorsJsContent;
3332         if (engineInstance_->GetDelegate()->GetAssetContent("vendors.js", vendorsJsContent)) {
3333             bool vendorsJsResult = CallEvalBuf(ctx, vendorsJsContent.c_str(), vendorsJsContent.size(),
3334                 "vendors.js", JS_EVAL_TYPE_MODULE, instanceId_);
3335             if (vendorsJsResult == JS_CALL_FAIL) {
3336                 LOGE("fail to execute load vendorsjs script");
3337             }
3338         }
3339         std::string code;
3340         std::string appMap;
3341         if (engineInstance_->GetDelegate()->GetAssetContent("app.js.map", appMap)) {
3342             page->SetAppMap(appMap);
3343         } else {
3344             LOGW("sourceMap of app.js is missing!");
3345         }
3346 
3347         if (engineInstance_->GetDelegate()->GetAssetContent("app.js", code)) {
3348             renderOption->Put("appCreate", "true");
3349             renderOption->Put("appCode", code.c_str());
3350         } else {
3351             LOGE("app.js is missing!");
3352         }
3353     } else {
3354         renderOption->Put("appCreate", "false");
3355     }
3356     optionStr = renderOption->ToString();
3357 }
3358 
LoadJs(const std::string & url,const RefPtr<JsAcePage> & page,bool isMainPage)3359 void QjsEngine::LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage)
3360 {
3361     LOGI("QjsEngine LoadJs");
3362     ACE_SCOPED_TRACE("QjsEngine::LoadJs");
3363     ACE_DCHECK(engineInstance_);
3364 
3365     engineInstance_->SetStagingPage(page);
3366     if (isMainPage) {
3367         ACE_DCHECK(!engineInstance_->GetRunningPage());
3368         engineInstance_->SetRunningPage(page);
3369     }
3370     JSContext* ctx = engineInstance_->GetQjsContext();
3371 
3372     // Create a stack-allocated handle scope.
3373     QJSHandleScope handleScope(ctx);
3374 
3375     // Memorize the context that this JSContext is working with.
3376     JS_SetContextOpaque(ctx, reinterpret_cast<void*>(AceType::RawPtr(engineInstance_)));
3377 
3378     JSValue globalObj = JS_GetGlobalObject(ctx);
3379     JSValue createInstanceFunc = QJSUtils::GetPropertyStr(ctx, globalObj, "createInstance");
3380     if (!JS_IsFunction(ctx, createInstanceFunc)) {
3381         LOGD("createInstance is not found, cannot load js!");
3382         JS_FreeValue(ctx, globalObj);
3383         return;
3384     }
3385 #ifdef ENABLE_JS_DEBUG
3386     std::string jsContent;
3387     if (!engineInstance_->GetDelegate()->GetAssetContent(url, jsContent)) {
3388         LOGE("js file load failed!");
3389         JS_FreeValue(ctx, globalObj);
3390         return;
3391     }
3392 #else
3393     JSValue jsCode = JS_UNDEFINED;
3394     auto pos = url.rfind(JS_EXT);
3395     if (pos != std::string::npos && pos == url.length() - (sizeof(JS_EXT) - 1)) {
3396         std::vector<uint8_t> binContent;
3397         if (engineInstance_->GetDelegate()->GetAssetContent(url.substr(0, pos) + BIN_EXT, binContent)) {
3398             jsCode =
3399                 CallReadObject(ctx, binContent.data(), binContent.size(), false, instanceId_, page->GetUrl().c_str());
3400             if (!JS_IsException(jsCode)) {
3401                 JS_FreeValue(ctx, jsCode);
3402                 jsCode = QJSUtils::GetPropertyStr(ctx, globalObj, JS_MAIN_ENTRY);
3403                 JS_SetPropertyStr(ctx, globalObj, JS_MAIN_ENTRY, JS_UNDEFINED);
3404             } else {
3405                 QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::READ_OBJECT_ERROR, instanceId_, page->GetUrl().c_str(),
3406                     page);
3407             }
3408         }
3409     }
3410 
3411     if (JS_IsFunction(ctx, jsCode)) {
3412         LOGI("Using binary source code");
3413     } else {
3414         std::string jsContent;
3415         if (!engineInstance_->GetDelegate()->GetAssetContent(url, jsContent)) {
3416             LOGE("js file load failed!");
3417             JS_FreeValue(ctx, globalObj);
3418             return;
3419         }
3420         jsCode = QJSUtils::NewStringLen(ctx, jsContent.c_str(), jsContent.size());
3421     }
3422 #endif
3423     std::string pageMap;
3424     if (engineInstance_->GetDelegate()->GetAssetContent(url + MAP_EXT, pageMap)) {
3425         page->SetPageMap(pageMap);
3426     } else {
3427         LOGW("source map of page load failed!");
3428     }
3429     std::string jsonData = page->GetPageParams();
3430     if (jsonData.empty()) {
3431         jsonData = "{}";
3432     }
3433     std::string optionStr;
3434     GetLoadOptions(optionStr, isMainPage, page);
3435     JSValue instanceId = QJSUtils::NewString(ctx, std::to_string(page->GetPageId()).c_str());
3436     JSValue renderOptions = QJSUtils::ParseJSON(ctx, optionStr.c_str(), optionStr.size(), nullptr);
3437     JSValue data = QJSUtils::ParseJSON(ctx, jsonData.c_str(), jsonData.size(), nullptr);
3438     JSValue info = QJSUtils::NewObject(ctx);
3439 #ifdef ENABLE_JS_DEBUG
3440     JSValue jsSrc = QJSUtils::NewStringLen(ctx, jsContent.c_str(), jsContent.length());
3441     JSValueConst argv[] = { instanceId, jsSrc, renderOptions, data, info };
3442 #else
3443     JSValueConst argv[] = { instanceId, jsCode, renderOptions, data, info };
3444 #endif
3445     JSValue retVal = QJSUtils::Call(ctx, createInstanceFunc, JS_UNDEFINED, countof(argv), argv);
3446 
3447     if (JS_IsException(retVal)) {
3448         LOGE("JS framework load js bundle failed!");
3449         JS_FreeValue(ctx, globalObj);
3450         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::LOAD_JS_BUNDLE_ERROR, instanceId_, page->GetUrl().c_str(), page);
3451         return;
3452     }
3453 
3454     JS_FreeValue(ctx, retVal);
3455     JS_FreeValue(ctx, globalObj);
3456     js_std_loop(ctx);
3457 }
3458 
UpdateRunningPage(const RefPtr<JsAcePage> & page)3459 void QjsEngine::UpdateRunningPage(const RefPtr<JsAcePage>& page)
3460 {
3461     ACE_DCHECK(engineInstance_);
3462     engineInstance_->SetRunningPage(page);
3463     js_std_loop(engineInstance_->GetQjsContext());
3464 }
3465 
UpdateStagingPage(const RefPtr<JsAcePage> & page)3466 void QjsEngine::UpdateStagingPage(const RefPtr<JsAcePage>& page)
3467 {
3468     ACE_DCHECK(engineInstance_);
3469     engineInstance_->SetStagingPage(page);
3470     js_std_loop(engineInstance_->GetQjsContext());
3471 }
3472 
ResetStagingPage()3473 void QjsEngine::ResetStagingPage()
3474 {
3475     ACE_DCHECK(engineInstance_);
3476     auto runningPage = engineInstance_->GetRunningPage();
3477     engineInstance_->ResetStagingPage(runningPage);
3478     js_std_loop(engineInstance_->GetQjsContext());
3479 }
3480 
DestroyPageInstance(int32_t pageId)3481 void QjsEngine::DestroyPageInstance(int32_t pageId)
3482 {
3483     LOGI("QjsEngine DestroyPageInstance");
3484     JSContext* ctx = engineInstance_->GetQjsContext();
3485     ACE_DCHECK(ctx);
3486 
3487     QJSHandleScope handleScope(ctx);
3488     JSValue globalObj = JS_GetGlobalObject(ctx);
3489     JSValue destroyInstanceFunc = QJSUtils::GetPropertyStr(ctx, globalObj, "destroyInstance");
3490     if (!JS_IsFunction(ctx, destroyInstanceFunc)) {
3491         LOGE("destroyInstance is not found, cannot destroy page instance!");
3492         JS_FreeValue(ctx, globalObj);
3493         return;
3494     }
3495 
3496     JSValue instanceId = QJSUtils::NewString(ctx, std::to_string(pageId).c_str());
3497     JSValueConst argv[] = { instanceId };
3498     JSValue retVal = QJSUtils::Call(ctx, destroyInstanceFunc, JS_UNDEFINED, countof(argv), argv);
3499 
3500     if (JS_IsException(retVal)) {
3501         LOGE("Qjs DestroyPageInstance FAILED!");
3502         JS_FreeValue(ctx, globalObj);
3503 
3504         auto page = engineInstance_->GetDelegate()->GetPage(pageId);
3505         if (page) {
3506             QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::DESTROY_PAGE_ERROR, instanceId_, page->GetUrl().c_str(),
3507                 page);
3508         } else {
3509             QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::DESTROY_PAGE_ERROR, instanceId_,
3510                 engineInstance_->GetRunningPage()->GetUrl().c_str(), engineInstance_->GetRunningPage());
3511         }
3512         return;
3513     }
3514 
3515     RunGarbageCollection();
3516     JS_FreeValue(ctx, globalObj);
3517     js_std_loop(engineInstance_->GetQjsContext());
3518 }
3519 
UpdateApplicationState(const std::string & packageName,Frontend::State state)3520 void QjsEngine::UpdateApplicationState(const std::string& packageName, Frontend::State state)
3521 {
3522     LOGI("UpdateApplicationState: destroy app instance from jsfwk, packageName %{public}s", packageName.c_str());
3523     JSContext* ctx = engineInstance_->GetQjsContext();
3524     ACE_DCHECK(ctx);
3525 
3526     std::string stateType;
3527     switch (state) {
3528         case Frontend::State::ON_CREATE:
3529             break;
3530         case Frontend::State::ON_DESTROY:
3531             stateType = "appDestroy";
3532             break;
3533         case Frontend::State::ON_SHOW:
3534             stateType = "appShow";
3535             break;
3536         case Frontend::State::ON_HIDE:
3537             stateType = "appHide";
3538             break;
3539         default:
3540             LOGE("error State: %d", state);
3541             break;
3542     }
3543 
3544     QJSHandleScope handleScope(ctx);
3545     JSValue globalObj = JS_GetGlobalObject(ctx);
3546     JSValue appDestroyFunc = QJSUtils::GetPropertyStr(ctx, globalObj, stateType.c_str());
3547     if (!JS_IsFunction(ctx, appDestroyFunc)) {
3548         LOGE("appDestroyFunc is not found, cannot destroy page instance!");
3549         JS_FreeValue(ctx, globalObj);
3550         return;
3551     }
3552 
3553     JSValue name = QJSUtils::NewString(ctx, packageName.c_str());
3554     JSValueConst argv[] = { name };
3555     JSValue retVal = QJSUtils::Call(ctx, appDestroyFunc, JS_UNDEFINED, countof(argv), argv);
3556 
3557     if (JS_IsException(retVal)) {
3558         LOGE("Qjs appDestroyFunc FAILED!");
3559         QJSUtils::JsStdDumpErrorAce(ctx, JsErrorType::DESTROY_APP_ERROR, instanceId_, nullptr,
3560             engineInstance_->GetRunningPage());
3561     }
3562 
3563     JS_FreeValue(ctx, globalObj);
3564     js_std_loop(engineInstance_->GetQjsContext());
3565 }
3566 
OnStartContinuation()3567 bool QjsEngine::OnStartContinuation()
3568 {
3569     JSContext* ctx = engineInstance_->GetQjsContext();
3570     QJSHandleScope handleScope(ctx);
3571     JSValue globalObj = JS_GetGlobalObject(ctx);
3572     JSValue appObj = QJSUtils::GetPropertyStr(ctx, globalObj, "aceapp");
3573     if (!JS_IsObject(appObj)) {
3574         LOGE("aceapp is not found.");
3575         return false;
3576     }
3577     JSValue defObj = QJSUtils::GetPropertyStr(ctx, appObj, "$def");
3578     if (!JS_IsObject(defObj)) {
3579         LOGE("$def is not found.");
3580         return false;
3581     }
3582     JSValue func = QJSUtils::GetPropertyStr(ctx, defObj, "onStartContinuation");
3583     if (!JS_IsFunction(ctx, func)) {
3584         LOGE("onStartContinuation is not found.");
3585         JS_FreeValue(ctx, globalObj);
3586         return false;
3587     }
3588     JSValueConst argv[] = {};
3589     JSValue ret = QJSUtils::Call(ctx, func, defObj, countof(argv), argv);
3590     std::string result = JS_ToCString(ctx, ret);
3591     js_std_loop(ctx);
3592     JS_FreeValue(ctx, globalObj);
3593     return (result == "true");
3594 }
3595 
OnCompleteContinuation(int32_t code)3596 void QjsEngine::OnCompleteContinuation(int32_t code)
3597 {
3598     JSContext* ctx = engineInstance_->GetQjsContext();
3599     QJSHandleScope handleScope(ctx);
3600     JSValue globalObj = JS_GetGlobalObject(ctx);
3601     JSValue appObj = QJSUtils::GetPropertyStr(ctx, globalObj, "aceapp");
3602     if (!JS_IsObject(appObj)) {
3603         LOGE("aceapp is not found.");
3604         return;
3605     }
3606     JSValue defObj = QJSUtils::GetPropertyStr(ctx, appObj, "$def");
3607     if (!JS_IsObject(defObj)) {
3608         LOGE("$def is not found.");
3609         return;
3610     }
3611     JSValue func = QJSUtils::GetPropertyStr(ctx, defObj, "onCompleteContinuation");
3612     if (!JS_IsFunction(ctx, func)) {
3613         LOGE("onCompleteContinuation is not found.");
3614         JS_FreeValue(ctx, globalObj);
3615         return;
3616     }
3617     JSValueConst argv[] = { JS_NewInt32(ctx, code) };
3618     QJSUtils::Call(ctx, func, defObj, countof(argv), argv);
3619     js_std_loop(ctx);
3620     JS_FreeValue(ctx, globalObj);
3621 }
3622 
OnRemoteTerminated()3623 void QjsEngine::OnRemoteTerminated()
3624 {
3625     JSContext* ctx = engineInstance_->GetQjsContext();
3626     QJSHandleScope handleScope(ctx);
3627     JSValue globalObj = JS_GetGlobalObject(ctx);
3628     JSValue appObj = QJSUtils::GetPropertyStr(ctx, globalObj, "aceapp");
3629     if (!JS_IsObject(appObj)) {
3630         LOGE("aceapp is not found.");
3631         return;
3632     }
3633     JSValue defObj = QJSUtils::GetPropertyStr(ctx, appObj, "$def");
3634     if (!JS_IsObject(defObj)) {
3635         LOGE("$def is not found.");
3636         return;
3637     }
3638     JSValue func = QJSUtils::GetPropertyStr(ctx, defObj, "onRemoteTerminated");
3639     if (!JS_IsFunction(ctx, func)) {
3640         LOGE("onRemoteTerminated is not found.");
3641         JS_FreeValue(ctx, globalObj);
3642         return;
3643     }
3644     JSValueConst argv[] = {};
3645     QJSUtils::Call(ctx, func, defObj, countof(argv), argv);
3646     js_std_loop(ctx);
3647     JS_FreeValue(ctx, globalObj);
3648 }
3649 
OnSaveData(std::string & data)3650 void QjsEngine::OnSaveData(std::string& data)
3651 {
3652     JSContext* ctx = engineInstance_->GetQjsContext();
3653     QJSHandleScope handleScope(ctx);
3654     JSValue globalObj = JS_GetGlobalObject(ctx);
3655     JSValue appObj = QJSUtils::GetPropertyStr(ctx, globalObj, "aceapp");
3656     if (!JS_IsObject(appObj)) {
3657         LOGE("aceapp is not found.");
3658         return;
3659     }
3660     JSValue defObj = QJSUtils::GetPropertyStr(ctx, appObj, "$def");
3661     if (!JS_IsObject(defObj)) {
3662         LOGE("$def is not found.");
3663         return;
3664     }
3665     JSValue func = QJSUtils::GetPropertyStr(ctx, defObj, "onSaveData");
3666     if (!JS_IsFunction(ctx, func)) {
3667         LOGE("onSaveData is not found.");
3668         JS_FreeValue(ctx, globalObj);
3669         return;
3670     }
3671     JSValue object = JS_NewObject(ctx);
3672     JSValueConst argv[] = { object };
3673     JSValue ret = QJSUtils::Call(ctx, func, defObj, countof(argv), argv);
3674     if (JS_ToCString(ctx, ret) == std::string("true")) {
3675         data = ScopedString::Stringify(ctx, object);
3676     }
3677     js_std_loop(ctx);
3678     JS_FreeValue(ctx, globalObj);
3679 }
3680 
OnRestoreData(const std::string & data)3681 bool QjsEngine::OnRestoreData(const std::string& data)
3682 {
3683     JSContext* ctx = engineInstance_->GetQjsContext();
3684     QJSHandleScope handleScope(ctx);
3685     JSValue globalObj = JS_GetGlobalObject(ctx);
3686     JSValue appObj = QJSUtils::GetPropertyStr(ctx, globalObj, "aceapp");
3687     if (!JS_IsObject(appObj)) {
3688         LOGE("aceapp is not found.");
3689         return false;
3690     }
3691     JSValue defObj = QJSUtils::GetPropertyStr(ctx, appObj, "$def");
3692     if (!JS_IsObject(defObj)) {
3693         LOGE("$def is not found.");
3694         return false;
3695     }
3696     JSValue func = QJSUtils::GetPropertyStr(ctx, defObj, "onRestoreData");
3697     if (!JS_IsFunction(ctx, func)) {
3698         LOGE("onRestoreData is not found.");
3699         JS_FreeValue(ctx, globalObj);
3700         return false;
3701     }
3702     JSValue jsonObj = JS_ParseJSON(ctx, data.c_str(), data.length(), "");
3703     if (JS_IsUndefined(jsonObj) || JS_IsException(jsonObj)) {
3704         LOGE("Parse json for restore data failed.");
3705         return false;
3706     }
3707     JSValueConst argv[] = { jsonObj };
3708     JSValue ret = QJSUtils::Call(ctx, func, defObj, countof(argv), argv);
3709     std::string result = JS_ToCString(ctx, ret);
3710     js_std_loop(ctx);
3711     JS_FreeValue(ctx, globalObj);
3712     return (result == "true");
3713 }
3714 
TimerCallback(const std::string & callbackId,const std::string & delay,bool isInterval)3715 void QjsEngine::TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval)
3716 {
3717     if (isInterval) {
3718         engineInstance_->CallJs(callbackId, std::string("{}"), true, true);
3719         engineInstance_->GetDelegate()->WaitTimer(callbackId, delay, isInterval, false);
3720     } else {
3721         engineInstance_->CallJs(callbackId, std::string("{}"), false, true);
3722         engineInstance_->GetDelegate()->ClearTimer(callbackId);
3723     }
3724 }
3725 
MediaQueryCallback(const std::string & callbackId,const std::string & args)3726 void QjsEngine::MediaQueryCallback(const std::string& callbackId, const std::string& args)
3727 {
3728     JsEngine::MediaQueryCallback(callbackId, args);
3729     if (!callbackId.empty() && engineInstance_) {
3730         engineInstance_->CallJs(callbackId.c_str(), args.c_str(), true, false);
3731     }
3732 }
3733 
RequestAnimationCallback(const std::string & callbackId,uint64_t timeStamp)3734 void QjsEngine::RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp)
3735 {
3736     if (engineInstance_) {
3737         engineInstance_->CallJs(callbackId.c_str(), std::to_string(timeStamp).c_str(), false, true);
3738         engineInstance_->GetDelegate()->CancelAnimationFrame(callbackId);
3739     }
3740 }
3741 
JsCallback(const std::string & callbackId,const std::string & args)3742 void QjsEngine::JsCallback(const std::string& callbackId, const std::string& args)
3743 {
3744     if (engineInstance_) {
3745         engineInstance_->CallJs(callbackId.c_str(), args.c_str(), true, false);
3746     }
3747 }
3748 
FireAsyncEvent(const std::string & eventId,const std::string & param)3749 void QjsEngine::FireAsyncEvent(const std::string& eventId, const std::string& param)
3750 {
3751     std::string callBuf = std::string("[{\"args\": [\"")
3752                               .append(eventId)
3753                               .append("\",")
3754                               .append(param)
3755                               .append("], \"method\":\"fireEvent\"}]");
3756     LOGD("FireAsyncEvent string: %{private}s", callBuf.c_str());
3757 
3758     ACE_DCHECK(engineInstance_);
3759     JSValue cppToJsRet = engineInstance_->FireJsEvent(callBuf);
3760     if (JS_IsException(cppToJsRet)) {
3761         LOGE("Qjs FireAsyncEvent FAILED !! jsCall: %{private}s", callBuf.c_str());
3762         QJSUtils::JsStdDumpErrorAce(engineInstance_->GetQjsContext(), JsErrorType::FIRE_EVENT_ERROR, instanceId_,
3763             nullptr, engineInstance_->GetRunningPage());
3764     }
3765     js_std_loop(engineInstance_->GetQjsContext());
3766     JS_FreeValue(engineInstance_->GetQjsContext(), cppToJsRet);
3767 }
3768 
FireSyncEvent(const std::string & eventId,const std::string & param)3769 void QjsEngine::FireSyncEvent(const std::string& eventId, const std::string& param)
3770 {
3771     std::string callBuf = std::string("[{\"args\": [\"")
3772                               .append(eventId)
3773                               .append("\",")
3774                               .append(param)
3775                               .append("], \"method\":\"fireEventSync\"}]");
3776     LOGD("FireSyncEvent string: %{private}s", callBuf.c_str());
3777 
3778     ACE_DCHECK(engineInstance_);
3779     JSValue cppToJsRet = engineInstance_->FireJsEvent(callBuf.c_str());
3780     if (JS_IsException(cppToJsRet)) {
3781         LOGE("Qjs FireSyncEvent FAILED !! jsCall: %{private}s", callBuf.c_str());
3782         QJSUtils::JsStdDumpErrorAce(engineInstance_->GetQjsContext(), JsErrorType::FIRE_EVENT_ERROR, instanceId_,
3783             nullptr, engineInstance_->GetRunningPage());
3784     }
3785     js_std_loop(engineInstance_->GetQjsContext());
3786     JS_FreeValue(engineInstance_->GetQjsContext(), cppToJsRet);
3787 }
3788 
FireExternalEvent(const std::string & componentId,const uint32_t nodeId,const bool isDestroy)3789 void QjsEngine::FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
3790 {
3791     ACE_DCHECK(engineInstance_);
3792     if (isDestroy) {
3793         return;
3794     }
3795     auto context = engineInstance_->GetQjsContext();
3796 
3797     auto page = engineInstance_->GetRunningPage();
3798     if (page == nullptr) {
3799         LOGE("FireExternalEvent GetRunningPage is nullptr");
3800         return;
3801     }
3802     std::string arguments;
3803     auto bridge = AceType::DynamicCast<QjsXComponentBridge>(page->GetXComponentBridgeById(nodeId));
3804     if (bridge) {
3805         bridge->HandleContext(context, nodeId, arguments);
3806         return;
3807     }
3808 }
3809 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)3810 void QjsEngine::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
3811 {
3812     ACE_DCHECK(engineInstance_);
3813     engineInstance_->SetJsMessageDispatcher(dispatcher);
3814 }
3815 
RunGarbageCollection()3816 void QjsEngine::RunGarbageCollection()
3817 {
3818     if (engineInstance_ && engineInstance_->GetQjsRuntime()) {
3819         JS_RunGC(engineInstance_->GetQjsRuntime());
3820     }
3821 }
3822 
GetGroupJsBridge()3823 RefPtr<GroupJsBridge> QjsEngine::GetGroupJsBridge()
3824 {
3825     return AceType::MakeRefPtr<QuickJsGroupJsBridge>();
3826 }
3827 
3828 } // namespace OHOS::Ace::Framework
3829