• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "bridge/declarative_frontend/jsview/js_navigation_stack.h"
17 
18 #include "bridge/common/utils/engine_helper.h"
19 #include "bridge/declarative_frontend/engine/js_converter.h"
20 #include "bridge/declarative_frontend/engine/functions/js_function.h"
21 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
22 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
23 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
24 #include "core/components_ng/base/ui_node.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/custom/custom_node.h"
27 #include "core/components_ng/pattern/navrouter/navdestination_model.h"
28 #include "core/components_v2/inspector/inspector_constants.h"
29 #include "frameworks/base/json/json_util.h"
30 
31 namespace OHOS::Ace::Framework {
32 namespace {
33 constexpr int32_t ARGC_COUNT_TWO = 2;
34 constexpr int32_t MAX_PARSE_DEPTH = 3;
35 constexpr uint32_t MAX_PARSE_LENGTH = 1024;
36 constexpr uint32_t MAX_PARSE_PROPERTY_SIZE = 15;
37 constexpr int32_t INVALID_DESTINATION_MODE = -1;
38 constexpr char JS_STRINGIFIED_UNDEFINED[] = "undefined";
39 constexpr char JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC[] = "getNativeStack";
40 constexpr char JS_NAV_PATH_STACK_SETPARENT_FUNC[] = "setParent";
41 
GetNapiEnv()42 napi_env GetNapiEnv()
43 {
44     auto engine = EngineHelper::GetCurrentEngine();
45     CHECK_NULL_RETURN(engine, nullptr);
46     NativeEngine* nativeEngine = engine->GetNativeEngine();
47     CHECK_NULL_RETURN(nativeEngine, nullptr);
48     return reinterpret_cast<napi_env>(nativeEngine);
49 }
50 }
51 
GetName()52 std::string JSRouteInfo::GetName()
53 {
54     return name_;
55 }
56 
SetName(const std::string & name)57 void JSRouteInfo::SetName(const std::string& name)
58 {
59     name_ = name;
60 }
61 
SetParam(const JSRef<JSVal> & param)62 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
63 {
64     param_ = param;
65 }
66 
GetParam() const67 JSRef<JSVal> JSRouteInfo::GetParam() const
68 {
69     return param_;
70 }
71 
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)72 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
73 {
74     // clean callback from old JSNavPathStack
75     UpdateOnStateChangedCallback(dataSourceObj_, nullptr);
76     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, nullptr);
77     dataSourceObj_ = dataSourceObj;
78     // add callback to new JSNavPathStack
79     RemoveStack();
80     UpdateOnStateChangedCallback(dataSourceObj_, onStateChangedCallback_);
81     auto checkNavDestinationExistsFunc = [weakStack = WeakClaim(this)](const JSRef<JSObject>& info) -> int32_t {
82         auto stack = weakStack.Upgrade();
83         if (stack == nullptr) {
84             return ERROR_CODE_INTERNAL_ERROR;
85         }
86         auto errorCode = stack->CheckNavDestinationExists(info);
87         if (errorCode != ERROR_CODE_NO_ERROR) {
88             stack->RemoveInvalidPage(info);
89         }
90         return errorCode;
91     };
92     UpdateCheckNavDestinationExistsFunc(dataSourceObj_, checkNavDestinationExistsFunc);
93 }
94 
UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,std::function<int32_t (JSRef<JSObject>)> checkFunc)95 void JSNavigationStack::UpdateCheckNavDestinationExistsFunc(JSRef<JSObject> obj,
96     std::function<int32_t(JSRef<JSObject>)> checkFunc)
97 {
98     if (obj->IsEmpty()) {
99         return;
100     }
101 
102     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
103     if (!property->IsFunction()) {
104         return;
105     }
106 
107     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
108     auto nativeStack = getNativeStackFunc->Call(obj);
109     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
110         return;
111     }
112 
113     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
114     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
115     CHECK_NULL_VOID(stack);
116 
117     stack->SetCheckNavDestinationExistsFunc(checkFunc);
118 }
119 
GetDataSourceObj()120 const JSRef<JSObject>& JSNavigationStack::GetDataSourceObj()
121 {
122     return dataSourceObj_;
123 }
124 
SetNavDestBuilderFunc(const JSRef<JSFunc> & navDestBuilderFunc)125 void JSNavigationStack::SetNavDestBuilderFunc(const JSRef<JSFunc>& navDestBuilderFunc)
126 {
127     navDestBuilderFunc_ = navDestBuilderFunc;
128 }
129 
IsEmpty()130 bool JSNavigationStack::IsEmpty()
131 {
132     return dataSourceObj_->IsEmpty();
133 }
134 
Pop()135 void JSNavigationStack::Pop()
136 {
137     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
138     if (dataSourceObj_->IsEmpty()) {
139         return;
140     }
141     auto popFunc = dataSourceObj_->GetProperty("pop");
142     if (!popFunc->IsFunction()) {
143         return;
144     }
145     auto func = JSRef<JSFunc>::Cast(popFunc);
146     JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
147 }
148 
Push(const std::string & name,const RefPtr<NG::RouteInfo> & routeInfo)149 void JSNavigationStack::Push(const std::string& name, const RefPtr<NG::RouteInfo>& routeInfo)
150 {
151     // obtain param from NavPathStack
152     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
153     JSRef<JSVal> param;
154     if (routeInfo) {
155         auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
156         param = jsRouteInfo->GetParam();
157     } else {
158         auto getParamByNameFunc = dataSourceObj_->GetProperty("getParamByName");
159         if (getParamByNameFunc->IsFunction()) {
160             auto getFunc = JSRef<JSFunc>::Cast(getParamByNameFunc);
161             auto funcArray = getFunc->Call(dataSourceObj_);
162             if (funcArray->IsArray()) {
163                 auto result = JSRef<JSArray>::Cast(funcArray);
164                 param = result->GetValueAt(0);
165             }
166         }
167     }
168     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
169     if (pushNameFunc->IsFunction()) {
170         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
171         JSRef<JSVal> params[2];
172         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
173         params[1] = param;
174         pushFunc->Call(dataSourceObj_, 2, params);
175     }
176 }
177 
PushName(const std::string & name,const JSRef<JSVal> & param)178 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
179 {
180     // obtain param from routeInfo
181     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
182     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
183     if (pushNameFunc->IsFunction()) {
184         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
185         JSRef<JSVal> params[2];
186         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
187         params[1] = param;
188         pushFunc->Call(dataSourceObj_, 2, params);
189     }
190 }
191 
Push(const std::string & name,int32_t index)192 void JSNavigationStack::Push(const std::string& name, int32_t index)
193 {
194     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
195     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
196     if (!getParamByIndexFunc->IsFunction()) {
197         return ;
198     }
199     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
200     if (!pushNameFunc->IsFunction()) {
201         return ;
202     }
203     auto getFunc = JSRef<JSFunc>::Cast(getParamByIndexFunc);
204     auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
205     auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
206     JSRef<JSVal> params[ARGC_COUNT_TWO];
207     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
208     params[1] = param;
209     pushFunc->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
210 }
211 
RemoveName(const std::string & name)212 void JSNavigationStack::RemoveName(const std::string& name)
213 {
214     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
215     if (dataSourceObj_->IsEmpty()) {
216         return;
217     }
218     auto removeByNameFunc = dataSourceObj_->GetProperty("removeByName");
219     if (!removeByNameFunc->IsFunction()) {
220         return;
221     }
222     auto func = JSRef<JSFunc>::Cast(removeByNameFunc);
223     JSRef<JSVal> params[1];
224     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
225     func->Call(dataSourceObj_, 1, params);
226 }
227 
RemoveIndex(int32_t index)228 void JSNavigationStack::RemoveIndex(int32_t index)
229 {
230     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
231     if (dataSourceObj_->IsEmpty()) {
232         return;
233     }
234     auto removeIndexFunc = dataSourceObj_->GetProperty("removeIndex");
235     if (removeIndexFunc->IsFunction()) {
236         auto func = JSRef<JSFunc>::Cast(removeIndexFunc);
237         JSRef<JSVal> params[1];
238         params[0] = JSRef<JSVal>::Make(ToJSValue(index));
239         func->Call(dataSourceObj_, 1, params);
240     }
241 }
242 
Clear()243 void JSNavigationStack::Clear()
244 {
245     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
246     if (dataSourceObj_->IsEmpty()) {
247         return;
248     }
249     auto clearFunc = dataSourceObj_->GetProperty("clear");
250     if (!clearFunc->IsFunction()) {
251         return;
252     }
253     auto func = JSRef<JSFunc>::Cast(clearFunc);
254     func->Call(dataSourceObj_);
255 }
256 
GetAllPathName()257 std::vector<std::string> JSNavigationStack::GetAllPathName()
258 {
259     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
260     if (dataSourceObj_->IsEmpty()) {
261         return {};
262     }
263     auto getAllPathNameFunc = dataSourceObj_->GetProperty("getAllPathName");
264     if (!getAllPathNameFunc->IsFunction()) {
265         return {};
266     }
267     auto func = JSRef<JSFunc>::Cast(getAllPathNameFunc);
268     auto funcArray = func->Call(dataSourceObj_);
269     if (!funcArray->IsArray()) {
270         return {};
271     }
272     auto array = JSRef<JSArray>::Cast(funcArray);
273     if (array->IsEmpty()) {
274         return {};
275     }
276     std::vector<std::string> pathNames;
277     for (size_t i = 0; i < array->Length(); i++) {
278         auto value = array->GetValueAt(i);
279         if (value->IsString()) {
280             pathNames.emplace_back(value->ToString());
281         }
282     }
283 
284     return pathNames;
285 }
286 
GetAllPathIndex()287 std::vector<int32_t> JSNavigationStack::GetAllPathIndex()
288 {
289     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
290     if (dataSourceObj_->IsEmpty()) {
291         return {};
292     }
293     auto getAllPathIndexFunc = dataSourceObj_->GetProperty("getAllPathIndex");
294     if (!getAllPathIndexFunc->IsFunction()) {
295         return {};
296     }
297     auto func = JSRef<JSFunc>::Cast(getAllPathIndexFunc);
298     auto funcArray = func->Call(dataSourceObj_);
299     if (!funcArray->IsArray()) {
300         return {};
301     }
302     auto array = JSRef<JSArray>::Cast(funcArray);
303     if (array->IsEmpty()) {
304         return {};
305     }
306     std::vector<int32_t> pathIndex;
307     for (size_t i = 0; i < array->Length(); i++) {
308         auto value = array->GetValueAt(i);
309         if (value->IsNumber()) {
310             pathIndex.emplace_back(value->ToNumber<int32_t>());
311         }
312     }
313 
314     return pathIndex;
315 }
316 
InitNavPathIndex(const std::vector<std::string> & pathNames)317 void JSNavigationStack::InitNavPathIndex(const std::vector<std::string>& pathNames)
318 {
319     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
320     if (dataSourceObj_->IsEmpty()) {
321         return;
322     }
323 
324     JSRef<JSArray> nameArray = JSRef<JSArray>::New();
325     JSRef<JSVal> params[1];
326     for (size_t i = 0; i < pathNames.size(); i++) {
327         JSRef<JSVal> info = JSRef<JSVal>::Make(ToJSValue(pathNames[i]));
328         nameArray->SetValueAt(i, info);
329     }
330     params[0] = nameArray;
331     auto initNavPathIndexFunc = dataSourceObj_->GetProperty("initNavPathIndex");
332     if (!initNavPathIndexFunc->IsFunction()) {
333         return;
334     }
335     auto func = JSRef<JSFunc>::Cast(initNavPathIndexFunc);
336     func->Call(dataSourceObj_, 1, params);
337 }
338 
SetDestinationIdToJsStack(int32_t index,const std::string & navDestinationId)339 void JSNavigationStack::SetDestinationIdToJsStack(int32_t index, const std::string& navDestinationId)
340 {
341     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
342     auto pathInfo = GetJsPathInfo(index);
343     if (pathInfo->IsEmpty()) {
344         return;
345     }
346     pathInfo->SetProperty<std::string>("navDestinationId", navDestinationId);
347 }
348 
CallByPushDestination(int32_t index)349 bool JSNavigationStack::CallByPushDestination(int32_t index)
350 {
351     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
352     auto pathInfo = GetJsPathInfo(index);
353     if (pathInfo->IsEmpty()) {
354         return false;
355     }
356     auto isPushDestination = pathInfo->GetPropertyValue<bool>("pushDestination", false);
357     return isPushDestination;
358 }
359 
CreateNodeByIndex(int32_t index,const WeakPtr<NG::UINode> & customNode)360 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<NG::UINode>& customNode)
361 {
362     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
363     auto name = GetNameByIndex(index);
364     auto param = GetParamByIndex(index);
365     RefPtr<NG::UINode> node;
366     if (GetNodeFromPreBuildList(index, name, param, node)) {
367         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get node from prebuild list");
368         return node;
369     }
370     RefPtr<NG::NavDestinationGroupNode> desNode;
371     NG::ScopedViewStackProcessor scopedViewStackProcessor;
372     int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
373     if (errorCode != ERROR_CODE_NO_ERROR) {
374         if (CallByPushDestination(index)) {
375             return nullptr;
376         }
377         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "can't find target destination by index, create empty node");
378         return AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
379     }
380     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
381     if (pattern) {
382         pattern->SetName(name);
383         pattern->SetIndex(index);
384         auto onPop = GetOnPopByIndex(index);
385         auto isEntry = GetIsEntryByIndex(index);
386         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "create destination node, isEntry %{public}d", isEntry);
387         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
388         pattern->SetNavPathInfo(pathInfo);
389         pattern->SetNavigationStack(WeakClaim(this));
390     }
391     return node;
392 }
393 
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo,const WeakPtr<NG::UINode> & customNode)394 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo,
395     const WeakPtr<NG::UINode>& customNode)
396 {
397     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
398     auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
399     if (!jsRouteInfo) {
400         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "route info is invalid");
401         return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
402     }
403     auto name = jsRouteInfo->GetName();
404     auto param = jsRouteInfo->GetParam();
405     RefPtr<NG::UINode> node;
406     RefPtr<NG::NavDestinationGroupNode> desNode;
407     int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
408     if (errorCode == ERROR_CODE_NO_ERROR) {
409         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
410         if (pattern) {
411             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param);
412             pattern->SetNavPathInfo(pathInfo);
413             pattern->SetName(name);
414             pattern->SetNavigationStack(WeakClaim(this));
415         }
416         return node;
417     }
418     return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
419 }
420 
SetJSExecutionContext(const JSExecutionContext & context)421 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
422 {
423     executionContext_ = context;
424 }
425 
GetNameByIndex(int32_t index)426 std::string JSNavigationStack::GetNameByIndex(int32_t index)
427 {
428     auto pathNames = GetAllPathName();
429     if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
430         return "";
431     }
432 
433     return pathNames[index];
434 }
435 
GetParamByIndex(int32_t index) const436 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
437 {
438     if (dataSourceObj_->IsEmpty()) {
439         return JSRef<JSVal>::Make();
440     }
441     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
442     if (!getParamByIndexFunc->IsFunction()) {
443         return JSRef<JSVal>::Make();
444     }
445     auto func = JSRef<JSFunc>::Cast(getParamByIndexFunc);
446     JSRef<JSVal> params[1];
447     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
448     return func->Call(dataSourceObj_, 1, params);
449 }
450 
GetOnPopByIndex(int32_t index) const451 JSRef<JSVal> JSNavigationStack::GetOnPopByIndex(int32_t index) const
452 {
453     if (dataSourceObj_->IsEmpty()) {
454         return JSRef<JSVal>::Make();
455     }
456     auto getOnPopByIndexFunc = dataSourceObj_->GetProperty("getOnPopByIndex");
457     if (!getOnPopByIndexFunc->IsFunction()) {
458         return JSRef<JSVal>::Make();
459     }
460     auto func = JSRef<JSFunc>::Cast(getOnPopByIndexFunc);
461     JSRef<JSVal> params[1];
462     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
463     return func->Call(dataSourceObj_, 1, params);
464 }
465 
GetIsEntryByIndex(int32_t index)466 bool JSNavigationStack::GetIsEntryByIndex(int32_t index)
467 {
468     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
469     if (dataSourceObj_->IsEmpty()) {
470         return false;
471     }
472     auto getIsEntryFunc = dataSourceObj_->GetProperty("getIsEntryByIndex");
473     if (!getIsEntryFunc->IsFunction()) {
474         return false;
475     }
476     auto func = JSRef<JSFunc>::Cast(getIsEntryFunc);
477     JSRef<JSVal> params[1];
478     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
479     auto result = func->Call(dataSourceObj_, 1, params);
480     if (!result->IsBoolean()) {
481         return false;
482     }
483     return result->ToBoolean();
484 }
485 
SetIsEntryByIndex(int32_t index,bool isEntry)486 void JSNavigationStack::SetIsEntryByIndex(int32_t index, bool isEntry)
487 {
488     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
489     if (dataSourceObj_->IsEmpty()) {
490         return;
491     }
492     auto setIsEntryFunc = dataSourceObj_->GetProperty("setIsEntryByIndex");
493     if (!setIsEntryFunc->IsFunction()) {
494         return;
495     }
496     auto func = JSRef<JSFunc>::Cast(setIsEntryFunc);
497     JSRef<JSVal> params[ARGC_COUNT_TWO];
498     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
499     params[1] = JSRef<JSVal>::Make(ToJSValue(isEntry));
500     func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
501 }
502 
GetNavDestinationNodeInUINode(RefPtr<NG::UINode> node,RefPtr<NG::NavDestinationGroupNode> & desNode)503 bool JSNavigationStack::GetNavDestinationNodeInUINode(
504     RefPtr<NG::UINode> node, RefPtr<NG::NavDestinationGroupNode>& desNode)
505 {
506     RefPtr<NG::CustomNode> customNode;
507     while (node) {
508         if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
509             customNode = AceType::DynamicCast<NG::CustomNode>(node);
510             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "render current custom node: %{public}s",
511                 customNode->GetCustomTag().c_str());
512             // record parent navigationNode before customNode is rendered in case of navDestinationNode
513             auto navigationNode = GetNavigationNode();
514             customNode->SetNavigationNode(navigationNode);
515             // render, and find deep further
516             customNode->Render();
517         } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
518             desNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(node);
519             if (desNode) {
520                 desNode->SetNavDestinationCustomNode(AceType::WeakClaim(AceType::RawPtr(customNode)));
521             }
522             return true;
523         }
524         auto children = node->GetChildren();
525         if (children.size() != 1) {
526             TAG_LOGI(AceLogTag::ACE_NAVIGATION,
527                 "router map is invalid, child size is not one: %{public}zu", children.size());
528         }
529         node = children.front();
530     }
531     return false;
532 }
533 
GetReplaceValue() const534 int32_t JSNavigationStack::GetReplaceValue() const
535 {
536     if (dataSourceObj_->IsEmpty()) {
537         return false;
538     }
539     auto replace = dataSourceObj_->GetProperty("isReplace");
540     return replace->ToNumber<int32_t>();
541 }
542 
UpdateReplaceValue(int32_t replaceValue) const543 void JSNavigationStack::UpdateReplaceValue(int32_t replaceValue) const
544 {
545     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
546     if (dataSourceObj_->IsEmpty()) {
547         return;
548     }
549     auto setIsReplaceFunc = dataSourceObj_->GetProperty("setIsReplace");
550     if (!setIsReplaceFunc->IsFunction()) {
551         return;
552     }
553     auto replaceFunc = JSRef<JSFunc>::Cast(setIsReplaceFunc);
554     JSRef<JSVal> params[1];
555     params[0] = JSRef<JSVal>::Make(ToJSValue(replaceValue));
556     replaceFunc->Call(dataSourceObj_, 1, params);
557 }
558 
GetRouteParam() const559 std::string JSNavigationStack::GetRouteParam() const
560 {
561     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
562     auto size = GetSize();
563     if (size > 0) {
564         auto param = GetParamByIndex(size - 1);
565         return ConvertParamToString(param, true);
566     }
567     return "";
568 }
569 
GetSize() const570 int32_t JSNavigationStack::GetSize() const
571 {
572     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
573     if (dataSourceObj_->IsEmpty()) {
574         return 0;
575     }
576     auto sizeFunc = dataSourceObj_->GetProperty("size");
577     if (!sizeFunc->IsFunction()) {
578         return 0;
579     }
580     auto func = JSRef<JSFunc>::Cast(sizeFunc);
581     auto jsValue = JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
582     if (jsValue->IsNumber()) {
583         return jsValue->ToNumber<int32_t>();
584     }
585     return 0;
586 }
587 
ConvertParamToString(const JSRef<JSVal> & param,bool needLimit) const588 std::string JSNavigationStack::ConvertParamToString(const JSRef<JSVal>& param, bool needLimit) const
589 {
590     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
591     if (param->IsBoolean()) {
592         bool ret = param->ToBoolean();
593         return ret ? "true" : "false";
594     } else if (param->IsNumber()) {
595         double ret = param->ToNumber<double>();
596         std::ostringstream oss;
597         oss<< ret;
598         return oss.str();
599     } else if (param->IsString()) {
600         std::string ret = param->ToString();
601         if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
602             return ret.substr(0, MAX_PARSE_LENGTH);
603         }
604         return ret;
605     } else if (param->IsObject()) {
606         JSRef<JSObject> obj = JSRef<JSObject>::Cast(param);
607         auto jsonObj = JsonUtil::Create(true);
608         ParseJsObject(jsonObj, obj, MAX_PARSE_DEPTH, needLimit);
609         return jsonObj->ToString();
610     }
611     return "";
612 }
613 
ParseJsObject(std::unique_ptr<JsonValue> & json,const JSRef<JSObject> & obj,int32_t depthLimit,bool needLimit) const614 void JSNavigationStack::ParseJsObject(
615     std::unique_ptr<JsonValue>& json, const JSRef<JSObject>& obj, int32_t depthLimit, bool needLimit) const
616 {
617     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
618     if (depthLimit == 0) {
619         return;
620     }
621     depthLimit--;
622     auto propertyNames = obj->GetPropertyNames();
623     if (!propertyNames->IsArray()) {
624         return;
625     }
626     size_t size = propertyNames->Length();
627     if (needLimit && size > MAX_PARSE_PROPERTY_SIZE) {
628         size = MAX_PARSE_PROPERTY_SIZE;
629     }
630     for (size_t i = 0; i < size; i++) {
631         JSRef<JSVal> name = propertyNames->GetValueAt(i);
632         if (!name->IsString()) {
633             continue;
634         }
635         auto propertyName = name->ToString();
636         auto key = propertyName.c_str();
637         JSRef<JSVal> value = obj->GetProperty(key);
638         if (value->IsBoolean()) {
639             bool ret = value->ToBoolean();
640             json->Put(key, ret ? "true" : "false");
641         } else if (value->IsNumber()) {
642             double ret = value->ToNumber<double>();
643             std::ostringstream oss;
644             oss << ret;
645             json->Put(key, oss.str().c_str());
646         } else if (value->IsString()) {
647             std::string ret = value->ToString();
648             if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
649                 json->Put(key, ret.substr(0, MAX_PARSE_LENGTH).c_str());
650             } else {
651                 json->Put(key, ret.c_str());
652             }
653         } else if (value->IsObject()) {
654             JSRef<JSObject> childObj = JSRef<JSObject>::Cast(value);
655             auto childJson = JsonUtil::Create(true);
656             ParseJsObject(childJson, childObj, depthLimit, needLimit);
657             json->Put(key, childJson);
658         }
659     }
660 }
661 
GetAnimatedValue() const662 bool JSNavigationStack::GetAnimatedValue() const
663 {
664     if (dataSourceObj_->IsEmpty()) {
665         return true;
666     }
667     auto animated = dataSourceObj_->GetProperty("animated");
668     return animated->ToBoolean();
669 }
670 
UpdateAnimatedValue(bool animated)671 void JSNavigationStack::UpdateAnimatedValue(bool animated)
672 {
673     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
674     if (dataSourceObj_->IsEmpty()) {
675         return;
676     }
677     auto setAnimatedFunc = dataSourceObj_->GetProperty("setAnimated");
678     if (!setAnimatedFunc->IsFunction()) {
679         return;
680     }
681     auto animatedFunc = JSRef<JSFunc>::Cast(setAnimatedFunc);
682     JSRef<JSVal> params[1];
683     params[0] = JSRef<JSVal>::Make(ToJSValue(animated));
684     animatedFunc->Call(dataSourceObj_, 1, params);
685 }
686 
687 
GetDisableAnimation() const688 bool JSNavigationStack::GetDisableAnimation() const
689 {
690     if (dataSourceObj_->IsEmpty()) {
691         return false;
692     }
693     auto disableAllAnimation = dataSourceObj_->GetProperty("disableAllAnimation");
694     return disableAllAnimation->ToBoolean();
695 }
696 
UpdateOnStateChangedCallback(JSRef<JSObject> obj,std::function<void ()> callback)697 void JSNavigationStack::UpdateOnStateChangedCallback(JSRef<JSObject> obj, std::function<void()> callback)
698 {
699     if (obj->IsEmpty()) {
700         return;
701     }
702 
703     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
704     if (!property->IsFunction()) {
705         return;
706     }
707 
708     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
709     auto nativeStack = getNativeStackFunc->Call(obj);
710     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
711         return;
712     }
713 
714     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
715     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
716     CHECK_NULL_VOID(stack);
717     stack->SetOnStateChangedCallback(callback);
718     // When switching the navigation stack, it is necessary to immediately trigger a refresh
719     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation necessary to immediately trigger a refresh");
720     stack->OnStateChanged();
721     stack->SetOnPopCallback([weakStack = AceType::WeakClaim(this)](const JSRef<JSVal>& param) {
722         auto navigationStack = weakStack.Upgrade();
723         CHECK_NULL_VOID(navigationStack);
724         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(navigationStack->executionContext_);
725         auto size = navigationStack->GetSize();
726         if (size == 0) {
727             return;
728         }
729         auto pathInfo = navigationStack->GetJsPathInfo(size - 1);
730         if (pathInfo->IsEmpty()) {
731             return;
732         }
733         auto navDestinationId = pathInfo->GetProperty("navDestinationId");
734         if (!navDestinationId->IsString()) {
735             return;
736         }
737         auto id = navDestinationId->ToString();
738         auto navPathList = navigationStack->GetAllNavDestinationNodes();
739         for (auto iter : navPathList) {
740             if (navigationStack->ExecutePopCallback(iter.second, std::atoi(id.c_str()), param)) {
741                 return;
742             }
743         }
744     });
745 }
746 
OnAttachToParent(RefPtr<NG::NavigationStack> parent)747 void JSNavigationStack::OnAttachToParent(RefPtr<NG::NavigationStack> parent)
748 {
749     auto parentStack = AceType::DynamicCast<JSNavigationStack>(parent);
750     if (!parentStack) {
751         return;
752     }
753 
754     SetJSParentStack(JSRef<JSVal>::Cast(parentStack->GetDataSourceObj()));
755 }
756 
OnDetachFromParent()757 void JSNavigationStack::OnDetachFromParent()
758 {
759     JSRef<JSVal> undefined(JSVal::Undefined());
760     SetJSParentStack(undefined);
761 }
762 
SetJSParentStack(JSRef<JSVal> parent)763 void JSNavigationStack::SetJSParentStack(JSRef<JSVal> parent)
764 {
765     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
766     if (dataSourceObj_->IsEmpty()) {
767         return;
768     }
769 
770     auto property = dataSourceObj_->GetProperty(JS_NAV_PATH_STACK_SETPARENT_FUNC);
771     if (!property->IsFunction()) {
772         return;
773     }
774 
775     auto func = JSRef<JSFunc>::Cast(property);
776     JSRef<JSVal> params[1];
777     params[0] = parent;
778     func->Call(dataSourceObj_, 1, params);
779 }
780 
RemoveInvalidPage(const JSRef<JSObject> & info)781 void JSNavigationStack::RemoveInvalidPage(const JSRef<JSObject>& info)
782 {
783     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
784     if (dataSourceObj_->IsEmpty()) {
785         return;
786     }
787     auto removeInvalidPage = dataSourceObj_->GetProperty("removeInvalidPage");
788     if (removeInvalidPage->IsFunction()) {
789         auto func = JSRef<JSFunc>::Cast(removeInvalidPage);
790         auto pathName = info->GetProperty("name");
791         auto param = info->GetProperty("param");
792         JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
793         func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
794     }
795 }
796 
SaveNodeToPreBuildList(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node)797 void JSNavigationStack::SaveNodeToPreBuildList(const std::string& name, const JSRef<JSVal>& param,
798     RefPtr<NG::UINode>& node)
799 {
800     preBuildNodeList_.emplace_back(name, param, node, GetSize() - 1);
801 }
802 
GetNodeFromPreBuildList(int32_t index,const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node)803 bool JSNavigationStack::GetNodeFromPreBuildList(int32_t index, const std::string& name,
804     const JSRef<JSVal>& param, RefPtr<NG::UINode>& node)
805 {
806     auto isJsObjEqual = [](const JSRef<JSVal>& objLeft, const JSRef<JSVal>& objRight) {
807         return (objLeft->IsEmpty() && objRight->IsEmpty()) ||
808             (objLeft->GetLocalHandle()->IsStrictEquals(objLeft->GetEcmaVM(), objRight->GetLocalHandle()));
809     };
810     for (auto it = preBuildNodeList_.begin(); it != preBuildNodeList_.end(); ++it) {
811         if (it->name == name && isJsObjEqual(it->param, param) && it->index == index) {
812             node = it->uiNode;
813             preBuildNodeList_.erase(it);
814             return true;
815         }
816     }
817     return false;
818 }
819 
ClearPreBuildNodeList()820 void JSNavigationStack::ClearPreBuildNodeList()
821 {
822     preBuildNodeList_.clear();
823 }
824 
CheckNavDestinationExists(const JSRef<JSObject> & navPathInfo)825 int32_t JSNavigationStack::CheckNavDestinationExists(const JSRef<JSObject>& navPathInfo)
826 {
827     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, ERROR_CODE_DESTINATION_NOT_FOUND);
828     auto pathName = navPathInfo->GetProperty("name");
829     auto param = navPathInfo->GetProperty("param");
830     JSRef<JSVal> params[ARGC_COUNT_TWO] = { pathName, param };
831     auto name = pathName->ToString();
832     RefPtr<NG::UINode> node;
833     auto navigationNode = AceType::DynamicCast<NG::NavigationGroupNode>(navigationNode_.Upgrade());
834     CHECK_NULL_RETURN(navigationNode, ERROR_CODE_INTERNAL_ERROR);
835     auto navigationPattern = AceType::DynamicCast<NG::NavigationPattern>(navigationNode->GetPattern());
836     CHECK_NULL_RETURN(navigationPattern, ERROR_CODE_INTERNAL_ERROR);
837     RefPtr<NG::NavDestinationGroupNode> desNode;
838     int32_t errorCode = LoadDestination(name, param, navigationPattern->GetParentCustomNode(),
839         node, desNode);
840     if (errorCode != ERROR_CODE_NO_ERROR) {
841         return errorCode;
842     }
843     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
844     if (pattern) {
845         auto onPop = navPathInfo->GetProperty("onPop");
846         auto isEntryVal = navPathInfo->GetProperty("isEntry");
847         bool isEntry = isEntryVal->IsBoolean() ? isEntryVal->ToBoolean() : false;
848         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
849         pattern->SetName(name);
850         pattern->SetIndex(GetSize() - 1);
851         pattern->SetNavPathInfo(pathInfo);
852         pattern->SetNavigationStack(WeakClaim(this));
853     }
854     SaveNodeToPreBuildList(name, param, node);
855     return ERROR_CODE_NO_ERROR;
856 }
857 
DumpStackInfo() const858 std::vector<std::string> JSNavigationStack::DumpStackInfo() const
859 {
860     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
861     std::vector<std::string> dumpInfos;
862     for (size_t i = 0; i < navPathList_.size(); ++i) {
863         const auto& name = navPathList_[i].first;
864         std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\"";
865         std::string param = ConvertParamToString(GetParamByIndex(i));
866         if (param.length() > 0) {
867             info += ", param: " + param;
868         }
869         info += " }";
870         dumpInfos.push_back(std::move(info));
871     }
872     return dumpInfos;
873 }
874 
FireNavigationInterception(bool isBefore,const RefPtr<NG::NavDestinationContext> & from,const RefPtr<NG::NavDestinationContext> & to,NG::NavigationOperation operation,bool isAnimated)875 void JSNavigationStack::FireNavigationInterception(bool isBefore, const RefPtr<NG::NavDestinationContext>& from,
876     const RefPtr<NG::NavDestinationContext>& to, NG::NavigationOperation operation, bool isAnimated)
877 {
878     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
879     std::string targetName = isBefore ? "willShow" : "didShow";
880     JSRef<JSFunc> targetFunc;
881     if (!CheckAndGetInterceptionFunc(targetName, targetFunc)) {
882         return;
883     }
884     const uint8_t argsNum = 4;
885     JSRef<JSVal> params[argsNum];
886     auto preDestination = AceType::DynamicCast<NG::NavDestinationContext>(from);
887     if (!preDestination) {
888         params[0] = JSRef<JSVal>::Make(ToJSValue("navBar"));
889     } else if (preDestination->GetIsEmpty()) {
890         params[0] = JSRef<JSObject>::New();
891     } else {
892         JSRef<JSObject> preObj = JSClass<JSNavDestinationContext>::NewInstance();
893         auto preProxy = Referenced::Claim(preObj->Unwrap<JSNavDestinationContext>());
894         preProxy->SetNavDestinationContext(from);
895         params[0] = preObj;
896     }
897 
898     auto topDestination = AceType::DynamicCast<NG::NavDestinationContext>(to);
899     if (!topDestination) {
900         params[1] = JSRef<JSVal>::Make(ToJSValue("navBar"));
901     } else if (topDestination->GetIsEmpty()) {
902         params[1] = JSRef<JSObject>::New();
903     } else {
904         JSRef<JSObject> topObj = JSClass<JSNavDestinationContext>::NewInstance();
905         auto topProxy = Referenced::Claim(topObj->Unwrap<JSNavDestinationContext>());
906         topProxy->SetNavDestinationContext(to);
907         params[1] = topObj;
908     }
909     const uint8_t operationIndex = 2;
910     params[operationIndex] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
911     const uint8_t animatedIndex = 3;
912     params[animatedIndex] = JSRef<JSVal>::Make(ToJSValue(isAnimated));
913     targetFunc->Call(JSRef<JSObject>(), argsNum, params);
914 }
915 
FireNavigationModeChange(NG::NavigationMode mode)916 void JSNavigationStack::FireNavigationModeChange(NG::NavigationMode mode)
917 {
918     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
919     JSRef<JSFunc> modeFunc;
920     if (!CheckAndGetInterceptionFunc("modeChange", modeFunc)) {
921         return;
922     }
923     JSRef<JSVal> params[1];
924     params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(mode)));
925     modeFunc->Call(JSRef<JSObject>(), 1, params);
926 }
927 
CheckAndGetInterceptionFunc(const std::string & name,JSRef<JSFunc> & func)928 bool JSNavigationStack::CheckAndGetInterceptionFunc(const std::string& name, JSRef<JSFunc>& func)
929 {
930     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
931     if (dataSourceObj_->IsEmpty()) {
932         return false;
933     }
934     JSRef<JSVal> delegateProp = dataSourceObj_->GetProperty("interception");
935     if (!delegateProp->IsObject()) {
936         return false;
937     }
938     JSRef<JSObject> delegate = JSRef<JSObject>::Cast(delegateProp);
939     JSRef<JSVal> funcProp = delegate->GetProperty(name.c_str());
940     if (!funcProp->IsFunction()) {
941         return false;
942     }
943     func = JSRef<JSFunc>::Cast(funcProp);
944     return true;
945 }
946 
LoadDestinationByBuilder(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)947 bool JSNavigationStack::LoadDestinationByBuilder(const std::string& name, const JSRef<JSVal>& param,
948     RefPtr<NG::UINode>& node, RefPtr<NG::NavDestinationGroupNode>& desNode)
949 {
950     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
951     if (navDestBuilderFunc_->IsEmpty()) {
952         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "Builder function is empty");
953         return false;
954     }
955     auto builderObj = JSRef<JSObject>::Cast(navDestBuilderFunc_);
956     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
957     JSRef<JSVal> params[number];
958     if (number >= 1) {
959         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
960     }
961     if (number >= ARGC_COUNT_TWO) {
962         params[1] = param;
963     }
964     navDestBuilderFunc_->Call(JSRef<JSObject>(), number, params);
965     node = NG::ViewStackProcessor::GetInstance()->Finish();
966     return GetNavDestinationNodeInUINode(node, desNode);
967 }
968 
LoadDestination(const std::string & name,const JSRef<JSVal> & param,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)969 int32_t JSNavigationStack::LoadDestination(const std::string& name, const JSRef<JSVal>& param,
970     const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node,
971     RefPtr<NG::NavDestinationGroupNode>& desNode)
972 {
973     NG::ScopedViewStackProcessor scopedViewStackProcessor;
974     // execute navdestination attribute builder
975     if (LoadDestinationByBuilder(name, param, node, desNode)) {
976         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "load destination by buildermap");
977         return ERROR_CODE_NO_ERROR;
978     }
979     // deal route config and execute route config builder
980     auto container = Container::Current();
981     auto navigationRoute = container->GetNavigationRoute();
982     if (!navigationRoute->HasLoaded(name)) {
983         int32_t res = navigationRoute->LoadPage(name);
984         if (res != 0) {
985             TAG_LOGE(AceLogTag::ACE_NAVIGATION, "load page failed: %{public}s", name.c_str());
986             return navDestBuilderFunc_->IsEmpty() ? ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED
987                 : ERROR_CODE_DESTINATION_NOT_FOUND;
988         }
989     }
990     auto parentCustomNode = AceType::DynamicCast<NG::CustomNode>(customNode.Upgrade());
991     CHECK_NULL_RETURN(parentCustomNode, ERROR_CODE_INTERNAL_ERROR);
992     auto thisObjTmp = parentCustomNode->FireThisFunc();
993     CHECK_NULL_RETURN(thisObjTmp, ERROR_CODE_INTERNAL_ERROR);
994     JSRef<JSObject> thisObj = *(JSRef<JSObject>*)(thisObjTmp);
995     auto engine = AceType::DynamicCast<Framework::JsiDeclarativeEngine>(EngineHelper::GetCurrentEngine());
996     CHECK_NULL_RETURN(engine, ERROR_CODE_INTERNAL_ERROR);
997     JSRef<JSObject> wrapBuilder = JSRef<JSObject>::Make(engine->GetNavigationBuilder(name).ToLocal());
998     if (wrapBuilder->IsEmpty()) {
999         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "wrap builder is empty: %{public}s", name.c_str());
1000         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1001     }
1002     auto builderProp = wrapBuilder->GetProperty("builder");
1003     if (!builderProp->IsFunction()) {
1004         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get builder failed: %{public}s", name.c_str());
1005         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1006     }
1007     auto builderObj = JSRef<JSObject>::Cast(builderProp);
1008     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
1009     JSRef<JSVal> params[number];
1010     if (number >= 1) {
1011         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
1012     }
1013     if (number >= ARGC_COUNT_TWO) {
1014         params[1] = param;
1015     }
1016     auto builder = JSRef<JSFunc>::Cast(builderProp);
1017     builder->Call(thisObj, number, params);
1018     node = NG::ViewStackProcessor::GetInstance()->Finish();
1019     if (!GetNavDestinationNodeInUINode(node, desNode)) {
1020         return ERROR_CODE_DESTINATION_NOT_FOUND;
1021     }
1022     return ERROR_CODE_NO_ERROR;
1023 }
1024 
GetJsIndexFromNativeIndex(int32_t index)1025 int32_t JSNavigationStack::GetJsIndexFromNativeIndex(int32_t index)
1026 {
1027     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
1028     if (dataSourceObj_->IsEmpty()) {
1029         return -1;
1030     }
1031     auto getIndexFunc = dataSourceObj_->GetProperty("getJsIndexFromNativeIndex");
1032     if (!getIndexFunc->IsFunction()) {
1033         return -1;
1034     }
1035     auto func = JSRef<JSFunc>::Cast(getIndexFunc);
1036     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1037     auto res = func->Call(dataSourceObj_, 1, &param);
1038     if (res->IsNumber()) {
1039         return res->ToNumber<int32_t>();
1040     }
1041     return -1;
1042 }
1043 
MoveIndexToTop(int32_t index)1044 void JSNavigationStack::MoveIndexToTop(int32_t index)
1045 {
1046     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1047     if (dataSourceObj_->IsEmpty()) {
1048         return;
1049     }
1050     auto moveIndexToTopFunc = dataSourceObj_->GetProperty("moveIndexToTop");
1051     if (!moveIndexToTopFunc->IsFunction()) {
1052         return;
1053     }
1054     auto func = JSRef<JSFunc>::Cast(moveIndexToTopFunc);
1055     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1056     func->Call(dataSourceObj_, 1, &param);
1057 }
1058 
UpdatePathInfoIfNeeded(RefPtr<NG::UINode> & uiNode,int32_t index)1059 void JSNavigationStack::UpdatePathInfoIfNeeded(RefPtr<NG::UINode>& uiNode, int32_t index)
1060 {
1061     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1062     bool needUpdate = GetNeedUpdatePathInfo(index);
1063     if (!needUpdate) {
1064         return;
1065     }
1066     SetNeedUpdatePathInfo(index, false);
1067     RefPtr<NG::NavDestinationGroupNode> desNode;
1068     if (!GetNavDestinationNodeInUINode(uiNode, desNode)) {
1069         return;
1070     }
1071     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
1072     if (!pattern) {
1073         return;
1074     }
1075 
1076     auto name = GetNameByIndex(index);
1077     auto param = GetParamByIndex(index);
1078     auto onPop = GetOnPopByIndex(index);
1079     auto isEntry = GetIsEntryByIndex(index);
1080     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "update destination node info, isEntry %{public}d", isEntry);
1081     auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
1082     pattern->SetNavPathInfo(pathInfo);
1083 }
1084 
GetNeedUpdatePathInfo(int32_t index)1085 bool JSNavigationStack::GetNeedUpdatePathInfo(int32_t index)
1086 {
1087     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1088     auto path = GetJsPathInfo(index);
1089     if (path->IsEmpty()) {
1090         return false;
1091     }
1092     auto needUpdate = path->GetProperty("needUpdate");
1093     if (!needUpdate->IsBoolean()) {
1094         return false;
1095     }
1096     return needUpdate->ToBoolean();
1097 }
1098 
SetNeedUpdatePathInfo(int32_t index,bool need)1099 void JSNavigationStack::SetNeedUpdatePathInfo(int32_t index, bool need)
1100 {
1101     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1102     auto path = GetJsPathInfo(index);
1103     if (path->IsEmpty()) {
1104         return;
1105     }
1106     path->SetProperty<bool>("needUpdate", need);
1107 }
1108 
RecoveryNavigationStack()1109 void JSNavigationStack::RecoveryNavigationStack()
1110 {
1111     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1112     navPathList_ = preNavPathList_;
1113     if (dataSourceObj_->IsEmpty()) {
1114         return;
1115     }
1116     JSRef<JSArray> pathArray = JSRef<JSArray>::New();
1117     for (int32_t index = 0; index < static_cast<int32_t>(navPathList_.size()); index++) {
1118         auto node = navPathList_[index].second;
1119         auto navDestinationGroupNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1120             NG::NavigationGroupNode::GetNavDestinationNode(node));
1121         if (!navDestinationGroupNode) {
1122             continue;
1123         }
1124         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(navDestinationGroupNode->GetPattern());
1125         if (!pattern) {
1126             continue;
1127         }
1128         auto context = pattern->GetNavDestinationContext();
1129         if (!context) {
1130             continue;
1131         }
1132         JSRef<JSObject> item = CreatePathInfoWithNecessaryProperty(context);
1133         pathArray->SetValueAt(index, item);
1134     }
1135     dataSourceObj_->SetPropertyObject("pathArray", pathArray);
1136 }
1137 
NeedBuildNewInstance(int32_t index)1138 bool JSNavigationStack::NeedBuildNewInstance(int32_t index)
1139 {
1140     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1141     auto pathInfo = GetJsPathInfo(index);
1142     if (pathInfo->IsEmpty()) {
1143         return false;
1144     }
1145     auto needBuildNewInstance = pathInfo->GetProperty("needBuildNewInstance");
1146     if (!needBuildNewInstance->IsBoolean()) {
1147         return false;
1148     }
1149     return needBuildNewInstance->ToBoolean();
1150 }
1151 
SetNeedBuildNewInstance(int32_t index,bool need)1152 void JSNavigationStack::SetNeedBuildNewInstance(int32_t index, bool need)
1153 {
1154     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1155     auto pathInfo = GetJsPathInfo(index);
1156     if (pathInfo->IsEmpty()) {
1157         return;
1158     }
1159     pathInfo->SetProperty<bool>("needBuildNewInstance", need);
1160 }
1161 
GetJsPathArray()1162 JSRef<JSArray> JSNavigationStack::GetJsPathArray()
1163 {
1164     if (dataSourceObj_->IsEmpty()) {
1165         return JSRef<JSArray>();
1166     }
1167     auto objArray = dataSourceObj_->GetProperty("pathArray");
1168     if (!objArray->IsArray()) {
1169         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navPathArray invalid!");
1170         return JSRef<JSArray>();
1171     }
1172     return JSRef<JSArray>::Cast(objArray);
1173 }
1174 
GetJsPathInfo(int32_t index)1175 JSRef<JSObject> JSNavigationStack::GetJsPathInfo(int32_t index)
1176 {
1177     auto navPathArray = GetJsPathArray();
1178     int32_t len = static_cast<int32_t>(navPathArray->Length());
1179     if (index < 0 || index >= len) {
1180         return JSRef<JSObject>();
1181     }
1182     auto pathInfo = navPathArray->GetValueAt(index);
1183     if (!pathInfo->IsObject()) {
1184         return JSRef<JSObject>();
1185     }
1186     return JSRef<JSObject>::Cast(pathInfo);
1187 }
1188 
CreatePathInfoWithNecessaryProperty(const RefPtr<NG::NavDestinationContext> & context)1189 JSRef<JSObject> JSNavigationStack::CreatePathInfoWithNecessaryProperty(
1190     const RefPtr<NG::NavDestinationContext>& context)
1191 {
1192     auto pathInfo = JSRef<JSObject>::New();
1193     CHECK_NULL_RETURN(context, pathInfo);
1194     auto jsPathInfo = AceType::DynamicCast<JSNavPathInfo>(context->GetNavPathInfo());
1195     CHECK_NULL_RETURN(jsPathInfo, pathInfo);
1196 
1197     pathInfo->SetProperty<std::string>("name", jsPathInfo->GetName());
1198     pathInfo->SetProperty<int32_t>("index", context->GetIndex());
1199     pathInfo->SetProperty<std::string>("navDestinationId", std::to_string(context->GetNavDestinationId()));
1200     pathInfo->SetProperty<bool>("isEntry", jsPathInfo->GetIsEntry());
1201     pathInfo->SetPropertyObject("param", jsPathInfo->GetParam());
1202     pathInfo->SetPropertyObject("onPop", jsPathInfo->GetOnPop());
1203     return pathInfo;
1204 }
1205 
GetStringifyParamByIndex(int32_t index) const1206 std::string JSNavigationStack::GetStringifyParamByIndex(int32_t index) const
1207 {
1208     auto env = GetNapiEnv();
1209     if (!env) {
1210         return JS_STRINGIFIED_UNDEFINED;
1211     }
1212     napi_handle_scope scope = nullptr;
1213     napi_open_handle_scope(env, &scope);
1214     if (scope == nullptr) {
1215         return JS_STRINGIFIED_UNDEFINED;
1216     }
1217     if (dataSourceObj_->IsEmpty()) {
1218         napi_close_handle_scope(env, scope);
1219         return JS_STRINGIFIED_UNDEFINED;
1220     }
1221     napi_value navPathStack = JsConverter::ConvertJsValToNapiValue(dataSourceObj_);
1222     napi_value getParamByIndex;
1223     napi_get_named_property(env, navPathStack, "getParamByIndex", &getParamByIndex);
1224     napi_value napiIndex;
1225     napi_create_int32(env, index, &napiIndex);
1226     napi_value param;
1227     napi_call_function(env, navPathStack, getParamByIndex, 1, &napiIndex, &param);
1228 
1229     napi_value globalValue;
1230     napi_get_global(env, &globalValue);
1231     napi_value jsonClass;
1232     napi_get_named_property(env, globalValue, "JSON", &jsonClass);
1233     napi_value stringifyFunc;
1234     napi_get_named_property(env, jsonClass, "stringify", &stringifyFunc);
1235     napi_value stringifyParam;
1236     if (napi_call_function(env, jsonClass, stringifyFunc, 1, &param, &stringifyParam) != napi_ok) {
1237         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Can not stringify current param!");
1238         napi_get_and_clear_last_exception(env, &stringifyParam);
1239         napi_close_handle_scope(env, scope);
1240         return JS_STRINGIFIED_UNDEFINED;
1241     }
1242     size_t len = 0;
1243     napi_get_value_string_utf8(env, stringifyParam, nullptr, 0, &len);
1244     std::unique_ptr<char[]> paramChar = std::make_unique<char[]>(len + 1);
1245     napi_get_value_string_utf8(env, stringifyParam, paramChar.get(), len + 1, &len);
1246     napi_close_handle_scope(env, scope);
1247     return paramChar.get();
1248 }
1249 
SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo> & navdestinationsInfo)1250 void JSNavigationStack::SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo>& navdestinationsInfo)
1251 {
1252     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1253     JSRef<JSArray> newPathArray = JSRef<JSArray>::New();
1254     for (int32_t index = 0; index < static_cast<int32_t>(navdestinationsInfo.size()); ++index) {
1255         auto infoName = navdestinationsInfo[index].name;
1256         auto infoParam = navdestinationsInfo[index].param;
1257         auto infoMode = navdestinationsInfo[index].mode;
1258 
1259         JSRef<JSObject> navPathInfo = JSRef<JSObject>::New();
1260         navPathInfo->SetProperty<std::string>("name", infoName);
1261         if (!infoParam.empty() && infoParam != JS_STRINGIFIED_UNDEFINED) {
1262             navPathInfo->SetPropertyObject("param", JSRef<JSObject>::New()->ToJsonObject(infoParam.c_str()));
1263         }
1264         navPathInfo->SetProperty<bool>("fromRecovery", true);
1265         navPathInfo->SetProperty<int32_t>("mode", infoMode);
1266         newPathArray->SetValueAt(index, navPathInfo);
1267     }
1268     dataSourceObj_->SetPropertyObject("pathArray", newPathArray);
1269     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Set navPathArray by recovery info success");
1270 }
1271 
IsFromRecovery(int32_t index)1272 bool JSNavigationStack::IsFromRecovery(int32_t index)
1273 {
1274     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1275     auto pathInfo = GetJsPathInfo(index);
1276     if (pathInfo->IsEmpty()) {
1277         return false;
1278     }
1279     auto fromRecovery = pathInfo->GetProperty("fromRecovery");
1280     if (!fromRecovery->IsBoolean()) {
1281         return false;
1282     }
1283     return fromRecovery->ToBoolean();
1284 }
1285 
SetFromRecovery(int32_t index,bool fromRecovery)1286 void JSNavigationStack::SetFromRecovery(int32_t index, bool fromRecovery)
1287 {
1288     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1289     auto pathInfo = GetJsPathInfo(index);
1290     if (pathInfo->IsEmpty()) {
1291         return;
1292     }
1293     pathInfo->SetProperty<bool>("fromRecovery", fromRecovery);
1294 }
1295 
GetRecoveredDestinationMode(int32_t index)1296 int32_t JSNavigationStack::GetRecoveredDestinationMode(int32_t index)
1297 {
1298     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
1299     auto pathInfo = GetJsPathInfo(index);
1300     if (pathInfo->IsEmpty()) {
1301         return INVALID_DESTINATION_MODE;
1302     }
1303     auto mode = pathInfo->GetProperty("mode");
1304     if (!mode->IsNumber()) {
1305         return INVALID_DESTINATION_MODE;
1306     }
1307     return mode->ToNumber<int32_t>();
1308 }
1309 
ExecutePopCallback(const RefPtr<NG::UINode> & uiNode,uint64_t navDestinationId,const JSRef<JSVal> & param)1310 bool JSNavigationStack::ExecutePopCallback(const RefPtr<NG::UINode>& uiNode,
1311     uint64_t navDestinationId, const JSRef<JSVal>& param)
1312 {
1313     auto navDestinationNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1314         NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
1315     CHECK_NULL_RETURN(navDestinationNode, false);
1316     auto pattern = navDestinationNode->GetPattern<NG::NavDestinationPattern>();
1317     CHECK_NULL_RETURN(pattern, false);
1318     if (pattern->GetNavDestinationId() != navDestinationId) {
1319         return false;
1320     }
1321     auto navPathInfo = AceType::DynamicCast<JSNavPathInfo>(pattern->GetNavPathInfo());
1322     CHECK_NULL_RETURN(navPathInfo, false);
1323     auto callback = navPathInfo->GetNavDestinationPopCallback();
1324     if (callback->IsEmpty()) {
1325         return false;
1326     }
1327     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "fire onPop callback: %{public}s", pattern->GetName().c_str());
1328     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1329     JSRef<JSVal> params[1];
1330     params[0] = param;
1331     callback->Call(JSRef<JSObject>(), 1, params);
1332     return true;
1333 }
1334 } // namespace OHOS::Ace::Framework
1335