• 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 "bridge/declarative_frontend/jsview/js_view.h"
17 
18 #include "base/log/ace_checker.h"
19 #include "base/log/ace_performance_check.h"
20 #include "base/log/ace_trace.h"
21 #include "base/memory/ace_type.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/system_properties.h"
24 #include "base/utils/utils.h"
25 #include "bridge/common/utils/engine_helper.h"
26 #include "bridge/declarative_frontend/engine/js_converter.h"
27 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
28 #include "bridge/declarative_frontend/engine/js_types.h"
29 #include "bridge/declarative_frontend/jsview/js_navigation_stack.h"
30 #include "bridge/declarative_frontend/jsview/js_view_stack_processor.h"
31 #include "bridge/declarative_frontend/jsview/models/view_full_update_model_impl.h"
32 #include "bridge/declarative_frontend/jsview/models/view_partial_update_model_impl.h"
33 #include "bridge/declarative_frontend/ng/declarative_frontend_ng.h"
34 #include "core/common/container.h"
35 #include "core/common/container_scope.h"
36 #include "core/common/layout_inspector.h"
37 #include "core/components_ng/base/observer_handler.h"
38 #include "core/components_ng/base/ui_node.h"
39 #include "core/components_ng/base/view_full_update_model.h"
40 #include "core/components_ng/base/view_full_update_model_ng.h"
41 #include "core/components_ng/base/view_partial_update_model.h"
42 #include "core/components_ng/base/view_partial_update_model_ng.h"
43 #include "core/components_ng/base/view_stack_model.h"
44 #include "core/components_ng/pattern/custom/custom_measure_layout_node.h"
45 #include "core/components_ng/pattern/recycle_view/recycle_dummy_node.h"
46 #include "core/components_v2/inspector/inspector_constants.h"
47 #include "interfaces/napi/kits/promptaction/prompt_controller.h"
48 
49 namespace OHOS::Ace {
50 
51 std::unique_ptr<ViewFullUpdateModel> ViewFullUpdateModel::instance_ = nullptr;
52 std::mutex ViewFullUpdateModel::mutex_;
53 
GetInstance()54 ViewFullUpdateModel* ViewFullUpdateModel::GetInstance()
55 {
56     if (!instance_) {
57         std::lock_guard<std::mutex> lock(mutex_);
58         if (!instance_) {
59 #ifdef NG_BUILD
60             instance_.reset(new NG::ViewFullUpdateModelNG());
61 #else
62             if (Container::IsCurrentUseNewPipeline()) {
63                 instance_.reset(new NG::ViewFullUpdateModelNG());
64             } else {
65                 instance_.reset(new Framework::ViewFullUpdateModelImpl());
66             }
67 #endif
68         }
69     }
70     return instance_.get();
71 }
72 
GetInstance()73 ViewPartialUpdateModel* ViewPartialUpdateModel::GetInstance()
74 {
75 #ifdef NG_BUILD
76     static NG::ViewPartialUpdateModelNG instance;
77     return &instance;
78 #else
79   if (Container::IsCurrentUseNewPipeline()) {
80       static NG::ViewPartialUpdateModelNG instance;
81       return &instance;
82   } else {
83       static Framework::ViewPartialUpdateModelImpl instance;
84       return &instance;
85   }
86 #endif
87 }
88 } // namespace OHOS::Ace
89 
90 namespace OHOS::Ace::Framework {
91 
JSBind(BindingTarget object)92 void JSView::JSBind(BindingTarget object)
93 {
94     JSViewPartialUpdate::JSBind(object);
95     JSViewFullUpdate::JSBind(object);
96 }
97 
RenderJSExecution()98 void JSView::RenderJSExecution()
99 {
100     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
101     if (!jsViewFunction_) {
102         return;
103     }
104     {
105         ACE_SCORING_EVENT("Component.AboutToRender");
106         jsViewFunction_->ExecuteAboutToRender();
107     }
108     if (!jsViewFunction_) {
109         return;
110     }
111     {
112         ACE_SCORING_EVENT("Component.Build");
113         ViewStackModel::GetInstance()->PushKey(viewId_);
114         jsViewFunction_->ExecuteRender();
115         ViewStackModel::GetInstance()->PopKey();
116     }
117     if (!jsViewFunction_) {
118         return;
119     }
120     {
121         ACE_SCORING_EVENT("Component.OnRenderDone");
122         jsViewFunction_->ExecuteOnRenderDone();
123         if (notifyRenderDone_) {
124             notifyRenderDone_();
125         }
126     }
127 }
128 
SyncInstanceId()129 void JSView::SyncInstanceId()
130 {
131     if (primaryStackSize_ >= PRIMARY_ID_STACK_SIZE) {
132         restoreInstanceIdStack_.emplace_back(Container::CurrentId());
133     } else {
134         primaryIdStack_[primaryStackSize_++] = Container::CurrentId();
135     }
136     ContainerScope::UpdateCurrent(instanceId_);
137 }
138 
RestoreInstanceId()139 void JSView::RestoreInstanceId()
140 {
141     if (primaryStackSize_ >= PRIMARY_ID_STACK_SIZE && !restoreInstanceIdStack_.empty()) {
142         // Checking primaryStackSize_ is necessary, because the pointer in restoreInstanceIdStack_ may be corrupted.
143         ContainerScope::UpdateCurrent(restoreInstanceIdStack_.back());
144         restoreInstanceIdStack_.pop_back();
145         return;
146     }
147     if (primaryStackSize_ == 0) {
148         ContainerScope::UpdateCurrent(-1);
149         return;
150     }
151     ContainerScope::UpdateCurrent(primaryIdStack_[--primaryStackSize_]);
152 }
153 
GetInstanceId(const JSCallbackInfo & info)154 void JSView::GetInstanceId(const JSCallbackInfo& info)
155 {
156     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(instanceId_)));
157 }
158 
JsSetCardId(int64_t cardId)159 void JSView::JsSetCardId(int64_t cardId)
160 {
161     cardId_ = cardId;
162 }
163 
JsGetCardId(const JSCallbackInfo & info)164 void JSView::JsGetCardId(const JSCallbackInfo& info)
165 {
166     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(cardId_)));
167 }
168 
GetNativeView(JSRef<JSObject> obj)169 JSView* JSView::GetNativeView(JSRef<JSObject> obj)
170 {
171     if (obj->HasProperty("nativeViewPartialUpdate")) {
172         JSRef<JSObject> nativeViewPartialUpdate = obj->GetProperty("nativeViewPartialUpdate");
173         return nativeViewPartialUpdate->Unwrap<JSView>();
174     }
175     return obj->Unwrap<JSView>();
176 }
177 
JSViewFullUpdate(const std::string & viewId,JSRef<JSObject> jsObject,JSRef<JSFunc> jsRenderFunction)178 JSViewFullUpdate::JSViewFullUpdate(const std::string& viewId, JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction)
179 {
180     viewId_ = viewId;
181     jsViewFunction_ = AceType::MakeRefPtr<ViewFunctions>(jsObject, jsRenderFunction);
182     jsViewObject_ = jsObject;
183 }
184 
~JSViewFullUpdate()185 JSViewFullUpdate::~JSViewFullUpdate()
186 {
187     jsViewFunction_.Reset();
188 };
189 
CreateViewNode(bool isTitleNode,bool isCustomAppBar)190 RefPtr<AceType> JSViewFullUpdate::CreateViewNode(bool isTitleNode, bool isCustomAppBar)
191 {
192     auto appearFunc = [weak = AceType::WeakClaim(this)] {
193         auto jsView = weak.Upgrade();
194         CHECK_NULL_VOID(jsView);
195         ContainerScope scope(jsView->GetInstanceId());
196         ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Appear");
197         if (jsView->viewNode_.Invalid() && jsView->jsViewFunction_) {
198             jsView->jsViewFunction_->ExecuteAppear();
199         }
200     };
201 
202     auto renderFunction = [weak = AceType::WeakClaim(this)]() -> RefPtr<AceType> {
203         auto jsView = weak.Upgrade();
204         CHECK_NULL_RETURN(jsView, nullptr);
205         ContainerScope scope(jsView->GetInstanceId());
206         return jsView->InternalRender();
207     };
208 
209     auto pageTransitionFunction = [weak = AceType::WeakClaim(this)]() {
210         auto jsView = weak.Upgrade();
211         if (!jsView || !jsView->jsViewFunction_) {
212             return;
213         }
214         {
215             ContainerScope scope(jsView->GetInstanceId());
216             ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Transition");
217             jsView->jsViewFunction_->ExecuteTransition();
218         }
219     };
220 
221     auto updateViewNodeFunction = [weak = AceType::WeakClaim(this)](const RefPtr<AceType>& node) {
222         auto jsView = weak.Upgrade();
223         if (jsView) {
224             jsView->viewNode_ = node;
225         }
226     };
227 
228     auto removeFunction = [weak = AceType::WeakClaim(this)]() -> void {
229         auto jsView = weak.Upgrade();
230         if (jsView && jsView->jsViewFunction_) {
231             ContainerScope scope(jsView->GetInstanceId());
232             jsView->jsViewFunction_->ExecuteDisappear();
233         }
234     };
235 
236     NodeInfo info = { .viewId = viewId_,
237         .appearFunc = std::move(appearFunc),
238         .renderFunc = std::move(renderFunction),
239         .removeFunc = std::move(removeFunction),
240         .updateNodeFunc = std::move(updateViewNodeFunction),
241         .isStatic = IsStatic() };
242 
243     if (jsViewFunction_ && jsViewFunction_->HasPageTransition()) {
244         info.pageTransitionFunc = std::move(pageTransitionFunction);
245     }
246 
247     return ViewFullUpdateModel::GetInstance()->CreateNode(std::move(info));
248 }
249 
InternalRender()250 RefPtr<AceType> JSViewFullUpdate::InternalRender()
251 {
252     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
253     needsUpdate_ = false;
254     RenderJSExecution();
255     CleanUpAbandonedChild();
256     jsViewFunction_->Destroy();
257     return ViewStackModel::GetInstance()->Finish();
258 }
259 
260 /**
261  * marks the JSView's composed component as needing update / rerender
262  */
MarkNeedUpdate()263 void JSViewFullUpdate::MarkNeedUpdate()
264 {
265     ACE_SCOPED_TRACE("JSView::MarkNeedUpdate");
266     needsUpdate_ = ViewFullUpdateModel::GetInstance()->MarkNeedUpdate(viewNode_);
267 }
268 
Destroy(JSView * parentCustomView)269 void JSViewFullUpdate::Destroy(JSView* parentCustomView)
270 {
271     DestroyChild(parentCustomView);
272     {
273         ACE_SCORING_EVENT("Component[" + viewId_ + "].Disappear");
274         jsViewFunction_->ExecuteDisappear();
275     }
276     {
277         ACE_SCORING_EVENT("Component[" + viewId_ + "].AboutToBeDeleted");
278         jsViewFunction_->ExecuteAboutToBeDeleted();
279     }
280     jsViewObject_.Reset();
281 }
282 
Create(const JSCallbackInfo & info)283 void JSViewFullUpdate::Create(const JSCallbackInfo& info)
284 {
285     ACE_DCHECK(!Container::IsCurrentUsePartialUpdate());
286 
287     if (info[0]->IsObject()) {
288         JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
289         auto* view = object->Unwrap<JSViewFullUpdate>();
290         if (view == nullptr) {
291             return;
292         }
293         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
294     }
295 }
296 
JSBind(BindingTarget object)297 void JSViewFullUpdate::JSBind(BindingTarget object)
298 {
299     JSClass<JSViewFullUpdate>::Declare("NativeViewFullUpdate");
300     JSClass<JSViewFullUpdate>::StaticMethod("create", &JSViewFullUpdate::Create);
301     JSClass<JSViewFullUpdate>::Method("markNeedUpdate", &JSViewFullUpdate::MarkNeedUpdate);
302     JSClass<JSViewFullUpdate>::Method("syncInstanceId", &JSViewFullUpdate::SyncInstanceId);
303     JSClass<JSViewFullUpdate>::Method("restoreInstanceId", &JSViewFullUpdate::RestoreInstanceId);
304     JSClass<JSViewFullUpdate>::CustomMethod("getInstanceId", &JSViewFullUpdate::GetInstanceId);
305     JSClass<JSViewFullUpdate>::Method("needsUpdate", &JSViewFullUpdate::NeedsUpdate);
306     JSClass<JSViewFullUpdate>::Method("markStatic", &JSViewFullUpdate::MarkStatic);
307     JSClass<JSViewFullUpdate>::Method("setCardId", &JSViewFullUpdate::JsSetCardId);
308     JSClass<JSViewFullUpdate>::CustomMethod("getCardId", &JSViewFullUpdate::JsGetCardId);
309     JSClass<JSViewFullUpdate>::CustomMethod("findChildById", &JSViewFullUpdate::FindChildById);
310     JSClass<JSViewFullUpdate>::CustomMethod("findChildByIdForPreview", &JSViewFullUpdate::FindChildByIdForPreview);
311     JSClass<JSViewFullUpdate>::InheritAndBind<JSViewAbstract>(object, ConstructorCallback, DestructorCallback);
312 }
313 
FindChildById(const JSCallbackInfo & info)314 void JSViewFullUpdate::FindChildById(const JSCallbackInfo& info)
315 {
316     if (info[0]->IsNumber() || info[0]->IsString()) {
317         std::string viewId = info[0]->ToString();
318         info.SetReturnValue(GetChildById(viewId));
319     } else {
320         JSException::Throw("%s", "JSView FindChildById with invalid arguments.");
321     }
322 }
323 
FindChildByIdForPreview(const JSCallbackInfo & info)324 void JSViewFullUpdate::FindChildByIdForPreview(const JSCallbackInfo& info)
325 {
326     if (!info[0]->IsNumber()) {
327         return;
328     }
329     std::string viewId = std::to_string(info[0]->ToNumber<int32_t>());
330     if (viewId_ == viewId) {
331         info.SetReturnValue(jsViewObject_);
332         return;
333     }
334     JSRef<JSObject> targetView = JSRef<JSObject>::New();
335     for (auto&& child : customViewChildren_) {
336         if (GetChildByViewId(viewId, child.second, targetView)) {
337             break;
338         }
339     }
340     auto view = targetView->Unwrap<JSViewFullUpdate>();
341     if (view) {
342         info.SetReturnValue(targetView);
343     }
344     return;
345 }
346 
GetChildByViewId(const std::string & viewId,JSRef<JSObject> & childView,JSRef<JSObject> & targetView)347 bool JSViewFullUpdate::GetChildByViewId(
348     const std::string& viewId, JSRef<JSObject>& childView, JSRef<JSObject>& targetView)
349 {
350     auto* view = childView->Unwrap<JSViewFullUpdate>();
351     CHECK_NULL_RETURN(view, false);
352     if (view->viewId_ == viewId) {
353         targetView = childView;
354         return true;
355     }
356     for (auto&& child : view->customViewChildren_) {
357         if (GetChildByViewId(viewId, child.second, targetView)) {
358             return true;
359         }
360     }
361     return false;
362 }
363 
ConstructorCallback(const JSCallbackInfo & info)364 void JSViewFullUpdate::ConstructorCallback(const JSCallbackInfo& info)
365 {
366     JSRef<JSObject> thisObj = info.This();
367     JSRef<JSVal> renderFunc = thisObj->GetProperty("render");
368     if (!renderFunc->IsFunction()) {
369         JSException::Throw("%s", "View derived classes must provide render(){...} function");
370         return;
371     }
372 
373     uint32_t argc = info.Length();
374     if (argc > 1 && (info[0]->IsNumber() || info[0]->IsString())) {
375         std::string viewId = info[0]->ToString();
376         auto instance = AceType::MakeRefPtr<JSViewFullUpdate>(viewId, info.This(), JSRef<JSFunc>::Cast(renderFunc));
377         auto context = info.GetExecutionContext();
378         instance->SetContext(context);
379         instance->IncRefCount();
380         info.SetReturnValue(AceType::RawPtr(instance));
381         if (!info[1]->IsUndefined() && info[1]->IsObject()) {
382             JSRef<JSObject> parentObj = JSRef<JSObject>::Cast(info[1]);
383             auto* parentView = parentObj->Unwrap<JSViewFullUpdate>();
384             if (parentView != nullptr) {
385                 auto id = parentView->AddChildById(viewId, info.This());
386                 instance->id_ = id;
387             }
388         }
389     } else {
390         JSException::Throw("%s", "JSView creation with invalid arguments.");
391     }
392 }
393 
DestructorCallback(JSViewFullUpdate * view)394 void JSViewFullUpdate::DestructorCallback(JSViewFullUpdate* view)
395 {
396     if (view == nullptr) {
397         return;
398     }
399     view->DecRefCount();
400 }
401 
DestroyChild(JSView * parentCustomView)402 void JSViewFullUpdate::DestroyChild(JSView* parentCustomView)
403 {
404     for (auto&& child : customViewChildren_) {
405         auto* view = child.second->Unwrap<JSView>();
406         if (view != nullptr) {
407             view->Destroy(this);
408         }
409         child.second.Reset();
410     }
411     customViewChildren_.clear();
412     for (auto&& lazyChild : customViewChildrenWithLazy_) {
413         auto* view = lazyChild.second->Unwrap<JSView>();
414         if (view != nullptr) {
415             view->Destroy(this);
416         }
417         lazyChild.second.Reset();
418     }
419     customViewChildrenWithLazy_.clear();
420 }
421 
CleanUpAbandonedChild()422 void JSViewFullUpdate::CleanUpAbandonedChild()
423 {
424     auto startIter = customViewChildren_.begin();
425     auto endIter = customViewChildren_.end();
426     std::vector<std::string> removedViewIds;
427     while (startIter != endIter) {
428         auto found = lastAccessedViewIds_.find(startIter->first);
429         if (found == lastAccessedViewIds_.end()) {
430             removedViewIds.emplace_back(startIter->first);
431             auto* view = startIter->second->Unwrap<JSView>();
432             if (view != nullptr) {
433                 view->Destroy(this);
434             }
435             startIter->second.Reset();
436         }
437         ++startIter;
438     }
439 
440     for (auto& viewId : removedViewIds) {
441         customViewChildren_.erase(viewId);
442     }
443 
444     lastAccessedViewIds_.clear();
445 }
446 
GetChildById(const std::string & viewId)447 JSRef<JSObject> JSViewFullUpdate::GetChildById(const std::string& viewId)
448 {
449     std::string id = ViewStackModel::GetInstance()->ProcessViewId(viewId);
450     auto found = customViewChildren_.find(id);
451     if (found != customViewChildren_.end()) {
452         ChildAccessedById(id);
453         return found->second;
454     }
455     auto lazyItem = customViewChildrenWithLazy_.find(id);
456     if (lazyItem != customViewChildrenWithLazy_.end()) {
457         return lazyItem->second;
458     }
459     return {};
460 }
461 
AddChildById(const std::string & viewId,const JSRef<JSObject> & obj)462 std::string JSViewFullUpdate::AddChildById(const std::string& viewId, const JSRef<JSObject>& obj)
463 {
464     std::string id = ViewStackModel::GetInstance()->ProcessViewId(viewId);
465     JSView* jsView = nullptr;
466     if (isLazyForEachProcessed_) {
467         auto result = customViewChildrenWithLazy_.try_emplace(id, obj);
468         if (!result.second) {
469             jsView = result.first->second->Unwrap<JSView>();
470             result.first->second = obj;
471         } else {
472             lazyItemGroups_[lazyItemGroupId_].emplace_back(id);
473         }
474     } else {
475         auto result = customViewChildren_.try_emplace(id, obj);
476         if (!result.second) {
477             jsView = result.first->second->Unwrap<JSView>();
478             result.first->second = obj;
479         }
480         ChildAccessedById(id);
481     }
482     if (jsView != nullptr) {
483         jsView->Destroy(this);
484     }
485     return id;
486 }
487 
RemoveChildGroupById(const std::string & viewId)488 void JSViewFullUpdate::RemoveChildGroupById(const std::string& viewId)
489 {
490     // js runtime may be released
491     CHECK_JAVASCRIPT_SCOPE_AND_RETURN;
492     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
493     auto iter = lazyItemGroups_.find(viewId);
494     if (iter == lazyItemGroups_.end()) {
495         return;
496     }
497     std::vector<std::string> removedViewIds;
498     for (auto&& item : iter->second) {
499         auto removeView = customViewChildrenWithLazy_.find(item);
500         if (removeView != customViewChildrenWithLazy_.end()) {
501             if (!removeView->second.IsEmpty()) {
502                 auto* view = removeView->second->Unwrap<JSView>();
503                 if (view != nullptr) {
504                     view->Destroy(this);
505                 }
506                 removeView->second.Reset();
507             }
508             removedViewIds.emplace_back(item);
509         }
510     }
511 
512     for (auto&& removeId : removedViewIds) {
513         customViewChildrenWithLazy_.erase(removeId);
514     }
515     lazyItemGroups_.erase(iter);
516 }
517 
ChildAccessedById(const std::string & viewId)518 void JSViewFullUpdate::ChildAccessedById(const std::string& viewId)
519 {
520     lastAccessedViewIds_.emplace(viewId);
521 }
522 
523 // =================================================================
524 
525 std::map<std::string, JSRef<JSObject>> JSViewStackProcessor::viewMap_;
526 
JSViewPartialUpdate(JSRef<JSObject> jsViewObject)527 JSViewPartialUpdate::JSViewPartialUpdate(JSRef<JSObject> jsViewObject)
528 {
529     jsViewFunction_ = AceType::MakeRefPtr<ViewFunctions>(jsViewObject);
530     // keep the reference to the JS View object to prevent GC
531     jsViewObject_ = jsViewObject;
532 }
533 
~JSViewPartialUpdate()534 JSViewPartialUpdate::~JSViewPartialUpdate()
535 {
536     jsViewFunction_.Reset();
537 };
538 
CreateViewNode(bool isTitleNode,bool isCustomAppBar)539 RefPtr<AceType> JSViewPartialUpdate::CreateViewNode(bool isTitleNode, bool isCustomAppBar)
540 {
541     auto updateViewIdFunc = [weak = AceType::WeakClaim(this)](const std::string& viewId) {
542         auto jsView = weak.Upgrade();
543         CHECK_NULL_VOID(jsView);
544         jsView->viewId_ = viewId;
545     };
546 
547     auto appearFunc = [weak = AceType::WeakClaim(this)]() {
548         auto jsView = weak.Upgrade();
549         CHECK_NULL_VOID(jsView);
550         ContainerScope scope(jsView->GetInstanceId());
551         ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Appear");
552         if (jsView->jsViewFunction_) {
553             jsView->jsViewFunction_->ExecuteAppear();
554         }
555     };
556 
557     auto didBuildFunc = [weak = AceType::WeakClaim(this)]() {
558         auto jsView = weak.Upgrade();
559         CHECK_NULL_VOID(jsView);
560         ContainerScope scope(jsView->GetInstanceId());
561         if (jsView->jsViewFunction_) {
562             jsView->jsViewFunction_->ExecuteDidBuild();
563         }
564     };
565 
566     auto renderFunction = [weak = AceType::WeakClaim(this)](int64_t deadline, bool& isTimeout) -> RefPtr<AceType> {
567         auto jsView = weak.Upgrade();
568         CHECK_NULL_RETURN(jsView, nullptr);
569         ContainerScope scope(jsView->GetInstanceId());
570         if (!jsView->isFirstRender_ && jsView->prebuildPhase_ != PrebuildPhase::EXECUTE_PREBUILD_CMD) {
571             return nullptr;
572         }
573         jsView->isFirstRender_ = false;
574         auto res = jsView->InitialRender(deadline, isTimeout);
575         return res;
576     };
577 
578     auto updateFunction = [weak = AceType::WeakClaim(this)]() -> void {
579         auto jsView = weak.Upgrade();
580         CHECK_NULL_VOID(jsView);
581         ContainerScope scope(jsView->GetInstanceId());
582         if (!jsView->needsUpdate_) {
583             return;
584         }
585         jsView->needsUpdate_ = false;
586         {
587             ACE_SCOPED_TRACE("JSView: ExecuteRerender");
588             jsView->jsViewFunction_->ExecuteRerender();
589         }
590         for (const UpdateTask& updateTask : jsView->pendingUpdateTasks_) {
591             ViewPartialUpdateModel::GetInstance()->FlushUpdateTask(updateTask);
592         }
593         jsView->pendingUpdateTasks_.clear();
594     };
595 
596     auto reloadFunction = [weak = AceType::WeakClaim(this)](bool deep) {
597         auto jsView = weak.Upgrade();
598         CHECK_NULL_VOID(jsView);
599         CHECK_NULL_VOID(jsView->jsViewFunction_);
600         ContainerScope scope(jsView->GetInstanceId());
601         jsView->jsViewFunction_->ExecuteReload(deep);
602     };
603 
604     // @Component level complete reload, can detect added/deleted frame nodes
605     auto completeReloadFunc = [weak = AceType::WeakClaim(this)](int64_t deadline, bool& isTimeout) -> RefPtr<AceType> {
606         auto jsView = weak.Upgrade();
607         CHECK_NULL_RETURN(jsView, nullptr);
608         ContainerScope scope(jsView->GetInstanceId());
609         return jsView->InitialRender(deadline, isTimeout);
610     };
611 
612     auto pageTransitionFunction = [weak = AceType::WeakClaim(this)]() {
613         auto jsView = weak.Upgrade();
614         CHECK_NULL_VOID(jsView);
615         CHECK_NULL_VOID(jsView->jsViewFunction_);
616         ContainerScope scope(jsView->GetInstanceId());
617         {
618             ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Transition");
619             jsView->jsViewFunction_->ExecuteTransition();
620         }
621     };
622 
623     auto removeFunction = [weak = AceType::WeakClaim(this)]() -> void {
624         auto jsView = weak.Upgrade();
625         CHECK_NULL_VOID(jsView);
626         ContainerScope scope(jsView->GetInstanceId());
627         jsView->Destroy(nullptr);
628         jsView->viewNode_.Reset();
629     };
630 
631     auto updateViewNodeFunction = [weak = AceType::WeakClaim(this)](const RefPtr<AceType>& node) {
632         auto jsView = weak.Upgrade();
633         CHECK_NULL_VOID(jsView);
634         jsView->viewNode_ = node;
635     };
636 
637     auto nodeUpdateFunc = [weak = AceType::WeakClaim(this)](int32_t nodeId) {
638         auto jsView = weak.Upgrade();
639         CHECK_NULL_VOID(jsView);
640         CHECK_NULL_VOID(jsView->jsViewFunction_);
641         ContainerScope scope(jsView->GetInstanceId());
642         jsView->jsViewFunction_->ExecuteForceNodeRerender(nodeId);
643     };
644 
645     auto hasNodeUpdateFunc = [weak = AceType::WeakClaim(this)](int32_t nodeId) -> bool {
646         auto jsView = weak.Upgrade();
647         CHECK_NULL_RETURN(jsView, false);
648         CHECK_NULL_RETURN(jsView->jsViewFunction_, false);
649         ContainerScope scope(jsView->GetInstanceId());
650         return jsView->jsViewFunction_->ExecuteHasNodeUpdateFunc(nodeId);
651     };
652 
653     auto recycleCustomNode = [weak = AceType::WeakClaim(this)](const RefPtr<NG::CustomNodeBase>& recycleNode) -> void {
654         auto jsView = weak.Upgrade();
655         CHECK_NULL_VOID(jsView);
656         CHECK_NULL_VOID(jsView->jsViewFunction_);
657         ContainerScope scope(jsView->GetInstanceId());
658         auto name = jsView->GetRecycleCustomNodeName();
659         if (name.empty()) {
660             return;
661         }
662         auto recycleUINode = AceType::DynamicCast<NG::UINode>(recycleNode);
663         recycleUINode->SetActive(false);
664         jsView->SetRecycleCustomNode(recycleNode);
665         jsView->jsViewFunction_->ExecuteRecycle(jsView->GetRecycleCustomNodeName());
666         if (!recycleNode->HasRecycleRenderFunc() && jsView->recycleCustomNode_) {
667             recycleUINode->SetJSViewActive(false, false, true);
668             jsView->jsViewFunction_->ExecuteAboutToRecycle();
669         }
670         recycleNode->ResetRecycle();
671     };
672 
673     auto setActiveFunc = [weak = AceType::WeakClaim(this)](bool active, bool isReuse = false) -> void {
674         auto jsView = weak.Upgrade();
675         CHECK_NULL_VOID(jsView);
676         ContainerScope scope(jsView->GetInstanceId());
677         CHECK_NULL_VOID(jsView->jsViewFunction_);
678         jsView->jsViewFunction_->ExecuteSetActive(active, isReuse);
679     };
680 
681     auto onDumpInfoFunc = [weak = AceType::WeakClaim(this)](const std::vector<std::string>& params) -> void {
682         auto jsView = weak.Upgrade();
683         CHECK_NULL_VOID(jsView);
684         ContainerScope scope(jsView->GetInstanceId());
685         CHECK_NULL_VOID(jsView->jsViewFunction_);
686         jsView->jsViewFunction_->ExecuteOnDumpInfo(params);
687     };
688 
689     auto onDumpInspectorFunc = [weak = AceType::WeakClaim(this)]() -> std::string {
690         auto jsView = weak.Upgrade();
691         CHECK_NULL_RETURN(jsView, "");
692         ContainerScope scope(jsView->GetInstanceId());
693         CHECK_NULL_RETURN(jsView->jsViewFunction_, "");
694         return jsView->jsViewFunction_->ExecuteOnDumpInfo();
695     };
696 
697     auto getThisFunc = [weak = AceType::WeakClaim(this)]() -> void* {
698         auto jsView = weak.Upgrade();
699         CHECK_NULL_RETURN(jsView, nullptr);
700         ContainerScope scope(jsView->GetInstanceId());
701         return (void*)&(jsView->jsViewObject_);
702     };
703 
704     auto recycleFunc = [weak = AceType::WeakClaim(this)]() -> void {
705         auto jsView = weak.Upgrade();
706         CHECK_NULL_VOID(jsView);
707         CHECK_NULL_VOID(jsView->jsViewFunction_);
708         ContainerScope scope(jsView->GetInstanceId());
709         jsView->jsViewFunction_->ExecuteAboutToRecycle();
710     };
711 
712     auto reuseFunc = [weak = AceType::WeakClaim(this)](void* params) -> void {
713         auto jsView = weak.Upgrade();
714         CHECK_NULL_VOID(jsView);
715         CHECK_NULL_VOID(jsView->jsViewFunction_);
716         ContainerScope scope(jsView->GetInstanceId());
717         jsView->jsViewFunction_->ExecuteAboutToReuse(params);
718     };
719 
720     NodeInfoPU info = { .appearFunc = std::move(appearFunc),
721         .didBuildFunc = std::move(didBuildFunc),
722         .renderFunc = std::move(renderFunction),
723         .updateFunc = std::move(updateFunction),
724         .removeFunc = std::move(removeFunction),
725         .updateNodeFunc = std::move(updateViewNodeFunction),
726         .pageTransitionFunc = std::move(pageTransitionFunction),
727         .reloadFunc = std::move(reloadFunction),
728         .completeReloadFunc = std::move(completeReloadFunc),
729         .nodeUpdateFunc = std::move(nodeUpdateFunc),
730         .hasNodeUpdateFunc = std::move(hasNodeUpdateFunc),
731         .recycleCustomNodeFunc = recycleCustomNode,
732         .setActiveFunc = std::move(setActiveFunc),
733         .onDumpInfoFunc = std::move(onDumpInfoFunc),
734         .onDumpInspectorFunc = std::move(onDumpInspectorFunc),
735         .getThisFunc = std::move(getThisFunc),
736         .recycleFunc = std::move(recycleFunc),
737         .reuseFunc = std::move(reuseFunc),
738         .hasMeasureOrLayout = jsViewFunction_->HasMeasure() || jsViewFunction_->HasLayout() ||
739                               jsViewFunction_->HasMeasureSize() || jsViewFunction_->HasPlaceChildren(),
740         .isStatic = IsStatic(),
741         .jsViewName = GetJSViewName(),
742         .isV2 = GetJSIsV2() };
743 
744     auto measureFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
745         auto jsView = weak.Upgrade();
746         CHECK_NULL_VOID(jsView);
747         ContainerScope scope(jsView->GetInstanceId());
748         jsView->jsViewFunction_->ExecuteMeasure(layoutWrapper);
749     };
750     if (jsViewFunction_->HasMeasure()) {
751         info.measureFunc = std::move(measureFunc);
752     }
753 
754     auto layoutFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
755         auto jsView = weak.Upgrade();
756         CHECK_NULL_VOID(jsView);
757         ContainerScope scope(jsView->GetInstanceId());
758         jsView->jsViewFunction_->ExecuteLayout(layoutWrapper);
759     };
760     if (jsViewFunction_->HasLayout()) {
761         info.layoutFunc = std::move(layoutFunc);
762     }
763 
764     if (jsViewFunction_->HasMeasureSize()) {
765         auto measureSizeFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
766             auto jsView = weak.Upgrade();
767             CHECK_NULL_VOID(jsView);
768             ContainerScope scope(jsView->GetInstanceId());
769             jsView->jsViewFunction_->ExecuteMeasureSize(layoutWrapper);
770         };
771         info.measureSizeFunc = std::move(measureSizeFunc);
772     }
773 
774     if (jsViewFunction_->HasPlaceChildren()) {
775         auto placeChildren = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
776             auto jsView = weak.Upgrade();
777             CHECK_NULL_VOID(jsView);
778             ContainerScope scope(jsView->GetInstanceId());
779             jsView->jsViewFunction_->ExecutePlaceChildren(layoutWrapper);
780         };
781         info.placeChildrenFunc = std::move(placeChildren);
782     }
783 
784     JSRef<JSObject> jsViewExtraInfo = jsViewObject_->GetProperty("extraInfo_");
785     if (!jsViewExtraInfo->IsUndefined()) {
786         JSRef<JSVal> jsPage = jsViewExtraInfo->GetProperty("page");
787         JSRef<JSVal> jsLine = jsViewExtraInfo->GetProperty("line");
788         JSRef<JSVal> jsColumn = jsViewExtraInfo->GetProperty("col");
789         info.extraInfo = {.page = jsPage->ToString(), .line = jsLine->ToNumber<int32_t>(),
790             .col = jsColumn->ToNumber<int32_t>()};
791     }
792 
793     if (isTitleNode) {
794         info.isCustomTitle = true;
795     }
796 
797     if (isCustomAppBar) {
798         info.isCustomAppBar = true;
799     }
800     auto node = ViewPartialUpdateModel::GetInstance()->CreateNode(std::move(info));
801     auto customMeasureLayoutNode = DynamicCast<NG::CustomMeasureLayoutNode>(node);
802     if (customMeasureLayoutNode) {
803         auto updateParamFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
804             auto jsView = weak.Upgrade();
805             CHECK_NULL_VOID(jsView);
806             ContainerScope scope(jsView->GetInstanceId());
807             jsView->jsViewFunction_->InitJsParam(layoutWrapper);
808         };
809         customMeasureLayoutNode->SetUpdateParamFunc(updateParamFunc);
810     }
811 #ifdef PREVIEW
812     auto uiNode = AceType::DynamicCast<NG::UINode>(node);
813     if (uiNode) {
814         Framework::JSViewStackProcessor::SetViewMap(std::to_string(uiNode->GetId()), jsViewObject_);
815     }
816 #endif
817 
818     if (AceChecker::IsPerformanceCheckEnabled()) {
819         auto uiNode = AceType::DynamicCast<NG::UINode>(node);
820         if (uiNode) {
821             auto codeInfo = EngineHelper::GetPositionOnJsCode();
822             uiNode->SetRow(codeInfo.first);
823             uiNode->SetCol(codeInfo.second);
824         }
825     }
826     return node;
827 }
828 
PrebuildComponentsInMultiFrame(int64_t deadline,bool & isTimeout)829 void JSViewPartialUpdate::PrebuildComponentsInMultiFrame(int64_t deadline, bool& isTimeout)
830 {
831     ACE_BUILD_TRACE_BEGIN("PrebuildComponentsInMultiFrame");
832     auto& prebuildComponentCmds = NG::ViewStackProcessor::GetInstance()->GetPrebuildComponentCmds();
833     if (!prebuildComponentCmds.empty()) {
834         SetPrebuildPhase(PrebuildPhase::EXECUTE_PREBUILD_CMD);
835     }
836     while (!prebuildComponentCmds.empty()) {
837         if (deadline > 0 && GetSysTimestamp() > deadline) {
838             isTimeout = true;
839             ACE_BUILD_TRACE_END()
840             return;
841         }
842         auto prebuildCmd = prebuildComponentCmds.front();
843         if (prebuildCmd.commandType == NG::PrebuildCompCmdType::FRONT) {
844             jsViewFunction_->ExecutePrebuildComponent();
845         } else if (prebuildCmd.commandType == NG::PrebuildCompCmdType::BACK) {
846             ACE_BUILD_TRACE_BEGIN("%s", prebuildCmd.commandName);
847             prebuildCmd.prebuildFunc();
848             ACE_BUILD_TRACE_END()
849         }
850         prebuildComponentCmds.pop();
851     }
852     isTimeout = false;
853     SetPrebuildPhase(PrebuildPhase::PREBUILD_DONE);
854     ACE_BUILD_TRACE_END()
855 }
856 
DoRenderJSExecution(int64_t deadline,bool & isTimeout)857 void JSViewPartialUpdate::DoRenderJSExecution(int64_t deadline, bool& isTimeout)
858 {
859     if (!executedRender_) {
860         if (deadline > 0 && jsViewFunction_->ExecuteIsEnablePrebuildInMultiFrame()) {
861             SetPrebuildPhase(PrebuildPhase::BUILD_PREBUILD_CMD, deadline);
862         }
863         jsViewFunction_->ExecuteRender();
864         executedRender_ = true;
865     }
866     PrebuildComponentsInMultiFrame(deadline, isTimeout);
867 }
868 
RenderJSExecutionForPrebuild(int64_t deadline,bool & isTimeout)869 void JSViewPartialUpdate::RenderJSExecutionForPrebuild(int64_t deadline, bool& isTimeout)
870 {
871     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
872     if (!jsViewFunction_) {
873         return;
874     }
875     if (!executedAboutToRender_) {
876         ACE_SCORING_EVENT("Component.AboutToRender");
877         jsViewFunction_->ExecuteAboutToRender();
878         executedAboutToRender_ = true;
879     }
880     if (!jsViewFunction_) {
881         return;
882     }
883     {
884         ACE_SCORING_EVENT("Component.Build");
885         ViewStackModel::GetInstance()->PushKey(viewId_);
886         DoRenderJSExecution(deadline, isTimeout);
887         ViewStackModel::GetInstance()->PopKey();
888         if (isTimeout) {
889             return;
890         }
891     }
892     if (!jsViewFunction_) {
893         return;
894     }
895     if (!executedOnRenderDone_) {
896         ACE_SCORING_EVENT("Component.OnRenderDone");
897         jsViewFunction_->ExecuteOnRenderDone();
898         if (notifyRenderDone_) {
899             notifyRenderDone_();
900         }
901         executedOnRenderDone_ = true;
902     }
903 }
904 
SetPrebuildPhase(PrebuildPhase prebuildPhase,int64_t deadline)905 void JSViewPartialUpdate::SetPrebuildPhase(PrebuildPhase prebuildPhase, int64_t deadline)
906 {
907     if (!jsViewFunction_) {
908         return;
909     }
910     prebuildPhase_ = prebuildPhase;
911     if (jsViewFunction_->ExecuteSetPrebuildPhase(prebuildPhase)) {
912         NG::ViewStackProcessor::GetInstance()->SetIsPrebuilding(
913             prebuildPhase == PrebuildPhase::BUILD_PREBUILD_CMD);
914     }
915 }
916 
InitialRender(int64_t deadline,bool & isTimeout)917 RefPtr<AceType> JSViewPartialUpdate::InitialRender(int64_t deadline, bool& isTimeout)
918 {
919     needsUpdate_ = false;
920     // When the pipeline is in OnIdle stage, deadline > 0, represents the expected end time of this frame
921     if (deadline > 0 || prebuildPhase_ == PrebuildPhase::EXECUTE_PREBUILD_CMD) {
922         RenderJSExecutionForPrebuild(deadline, isTimeout);
923         if (isTimeout) {
924             return nullptr;
925         }
926     } else {
927         RenderJSExecution();
928     }
929     return ViewStackModel::GetInstance()->Finish();
930 }
931 
932 // parentCustomView in not used by PartialUpdate
Destroy(JSView * parentCustomView)933 void JSViewPartialUpdate::Destroy(JSView* parentCustomView)
934 {
935     if (jsViewFunction_ == nullptr) {
936         // already called Destroy before
937         return;
938     }
939     {
940         ACE_SCORING_EVENT("Component[" + viewId_ + "].Disappear");
941         jsViewFunction_->ExecuteDisappear();
942     }
943     {
944         ACE_SCORING_EVENT("Component[" + viewId_ + "].AboutToBeDeleted");
945         jsViewFunction_->ExecuteAboutToBeDeleted();
946     }
947     pendingUpdateTasks_.clear();
948     jsViewFunction_->Destroy();
949     jsViewFunction_.Reset();
950 
951     // release reference to JS view object, and allow GC, calls DestructorCallback
952     jsViewObject_.Reset();
953 }
954 
MarkNeedUpdate()955 void JSViewPartialUpdate::MarkNeedUpdate()
956 {
957     needsUpdate_ = ViewPartialUpdateModel::GetInstance()->MarkNeedUpdate(viewNode_);
958 }
959 
960 /**
961  * in JS View.create(new View(...));
962  * used for FullRender case, not for re-render case
963  */
Create(const JSCallbackInfo & info)964 void JSViewPartialUpdate::Create(const JSCallbackInfo& info)
965 {
966     ACE_DCHECK(Container::IsCurrentUsePartialUpdate());
967 
968     if (info[0]->IsObject()) {
969         JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
970         auto view = object->Unwrap<JSView>();
971         if (view == nullptr) {
972             LOGE("View is null");
973             return;
974         }
975         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
976     }
977 }
978 
979 enum {
980     PARAM_VIEW_OBJ = 0,
981     PARAM_IS_RECYCLE,
982     PARAM_NODE_NAME,
983     PARAM_RECYCLE_UPDATE_FUNC,
984 
985     PARAM_SIZE,
986 };
987 
ParseRecycleParams(const JSCallbackInfo & info,JSRef<JSVal> (& params)[PARAM_SIZE])988 bool ParseRecycleParams(const JSCallbackInfo& info, JSRef<JSVal> (&params)[PARAM_SIZE])
989 {
990     if (info.Length() != PARAM_SIZE) {
991         return false;
992     }
993     if (!info[PARAM_VIEW_OBJ]->IsObject()) {
994         return false;
995     }
996     if (!info[PARAM_IS_RECYCLE]->IsBoolean()) {
997         return false;
998     }
999     if (!info[PARAM_RECYCLE_UPDATE_FUNC]->IsFunction()) {
1000         return false;
1001     }
1002 
1003     for (int32_t idx = PARAM_VIEW_OBJ; idx < PARAM_SIZE; ++idx) {
1004         params[idx] = info[idx];
1005     }
1006     return true;
1007 }
1008 
1009 /**
1010  * in JS ViewPU.createRecycle(...)
1011  * create a recyclable custom node
1012  */
CreateRecycle(const JSCallbackInfo & info)1013 void JSViewPartialUpdate::CreateRecycle(const JSCallbackInfo& info)
1014 {
1015     ACE_DCHECK(Container::IsCurrentUsePartialUpdate());
1016 
1017     JSRef<JSVal> params[PARAM_SIZE];
1018     if (!ParseRecycleParams(info, params)) {
1019         return;
1020     }
1021 
1022     auto viewObj = JSRef<JSObject>::Cast(params[PARAM_VIEW_OBJ]);
1023     JSRef<JSObject> nativeViewPartialUpdate = viewObj->GetProperty("nativeViewPartialUpdate");
1024     auto* view = nativeViewPartialUpdate->Unwrap<JSViewPartialUpdate>();
1025     if (!view) {
1026         return;
1027     }
1028     if (info[PARAM_NODE_NAME]->IsUndefined()) {
1029         view->SetRecycleCustomNodeName("");
1030         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
1031         return;
1032     }
1033     auto recycle = params[PARAM_IS_RECYCLE]->ToBoolean();
1034     auto nodeName = params[PARAM_NODE_NAME]->ToString();
1035     auto jsRecycleUpdateFunc =
1036         AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(params[PARAM_RECYCLE_UPDATE_FUNC]));
1037     auto recycleUpdateFunc = [weak = AceType::WeakClaim(view), execCtx = info.GetExecutionContext(),
1038                                  func = std::move(jsRecycleUpdateFunc)]() -> void {
1039         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1040         auto jsView = weak.Upgrade();
1041         CHECK_NULL_VOID(jsView);
1042         jsView->SetIsRecycleRerender(true);
1043         func->ExecuteJS();
1044         jsView->SetIsRecycleRerender(false);
1045     };
1046 
1047     // update view and node property
1048     view->SetRecycleCustomNodeName(nodeName);
1049 
1050     RefPtr<AceType> node;
1051 
1052     // get or create recycle node
1053     if (recycle) {
1054         node = view->GetCachedRecycleNode();
1055         AceType::DynamicCast<NG::CustomNodeBase>(node)->SetRecycleRenderFunc(std::move(recycleUpdateFunc));
1056     } else {
1057         node = view->CreateViewNode();
1058     }
1059     auto* stack = NG::ViewStackProcessor::GetInstance();
1060     auto dummyNode = NG::RecycleDummyNode::WrapRecycleDummyNode(node, stack->GetRecycleNodeId());
1061     ViewStackModel::GetInstance()->Push(dummyNode, true);
1062 }
1063 
OnDumpInfo(const std::vector<std::string> & params)1064 void JSViewPartialUpdate::OnDumpInfo(const std::vector<std::string>& params)
1065 {
1066     CHECK_NULL_VOID(jsViewFunction_);
1067     jsViewFunction_->ExecuteOnDumpInfo(params);
1068 }
1069 
JSGetNavDestinationInfo(const JSCallbackInfo & info)1070 void JSViewPartialUpdate::JSGetNavDestinationInfo(const JSCallbackInfo& info)
1071 {
1072     std::shared_ptr<OHOS::Ace::NG::NavDestinationInfo> result;
1073     if (info[0]->IsBoolean()) {
1074         if (info[0]->ToBoolean()) {
1075             result = NG::UIObserverHandler::GetInstance().GetNavigationInnerState(GetViewNode());
1076         } else {
1077             result = NG::UIObserverHandler::GetInstance().GetNavigationOuterState(GetViewNode());
1078         }
1079     } else {
1080         result = NG::UIObserverHandler::GetInstance().GetNavigationState(GetViewNode());
1081     }
1082     if (result) {
1083         JSRef<JSObject> obj = JSRef<JSObject>::New();
1084         obj->SetProperty<std::string>("navigationId", result->navigationId);
1085         obj->SetProperty<std::string>("name", result->name);
1086         obj->SetProperty<int32_t>("state", static_cast<int32_t>(result->state));
1087         obj->SetProperty<int32_t>("index", result->index);
1088         obj->SetPropertyObject("param", JsConverter::ConvertNapiValueToJsVal(result->param));
1089         obj->SetProperty<std::string>("navDestinationId", result->navDestinationId);
1090         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
1091             obj->SetProperty<int32_t>("mode", static_cast<int32_t>(result->mode));
1092             obj->SetProperty<int32_t>("uniqueId", result->uniqueId);
1093         }
1094         info.SetReturnValue(obj);
1095     }
1096 }
1097 
JSGetRouterPageInfo(const JSCallbackInfo & info)1098 void JSViewPartialUpdate::JSGetRouterPageInfo(const JSCallbackInfo& info)
1099 {
1100     auto result = NG::UIObserverHandler::GetInstance().GetRouterPageState(GetViewNode());
1101     if (result) {
1102         JSRef<JSObject> obj = JSRef<JSObject>::New();
1103         auto jsContext = JsConverter::ConvertNapiValueToJsVal(result->context);
1104         obj->SetPropertyObject("context", jsContext);
1105         obj->SetProperty<int32_t>("index", result->index);
1106         obj->SetProperty<std::string>("name", result->name);
1107         obj->SetProperty<std::string>("path", result->path);
1108         obj->SetProperty<int32_t>("state", static_cast<int32_t>(result->state));
1109         obj->SetProperty<std::string>("pageId", result->pageId);
1110         info.SetReturnValue(obj);
1111     }
1112 }
1113 
JSGetNavigationInfo(const JSCallbackInfo & info)1114 void JSViewPartialUpdate::JSGetNavigationInfo(const JSCallbackInfo& info)
1115 {
1116     ContainerScope scope(GetInstanceId());
1117     auto node = AceType::DynamicCast<NG::UINode>(this->GetViewNode());
1118     CHECK_NULL_VOID(node);
1119     auto pipeline = node->GetContext();
1120     CHECK_NULL_VOID(pipeline);
1121     auto navigationMgr = pipeline->GetNavigationManager();
1122     CHECK_NULL_VOID(navigationMgr);
1123     auto result = navigationMgr->GetNavigationInfo(GetViewNode());
1124     CHECK_NULL_VOID(result);
1125     auto stack = result->pathStack.Upgrade();
1126     CHECK_NULL_VOID(stack);
1127     auto jsStack = AceType::DynamicCast<JSNavigationStack>(stack);
1128     CHECK_NULL_VOID(jsStack);
1129     auto navPathStackObj = jsStack->GetDataSourceObj();
1130     CHECK_NULL_VOID(!navPathStackObj->IsEmpty());
1131     JSRef<JSObject> obj = JSRef<JSObject>::New();
1132     obj->SetProperty<std::string>("navigationId", result->navigationId);
1133     obj->SetPropertyObject("pathStack", navPathStackObj);
1134     info.SetReturnValue(obj);
1135 }
1136 
JSGetUIContext(const JSCallbackInfo & info)1137 void JSViewPartialUpdate::JSGetUIContext(const JSCallbackInfo& info)
1138 {
1139     ContainerScope scope(GetInstanceId());
1140     auto container = Container::Current();
1141     CHECK_NULL_VOID(container);
1142     auto frontend = container->GetFrontend();
1143     CHECK_NULL_VOID(frontend);
1144     auto context = frontend->GetContextValue();
1145     auto jsVal = JsConverter::ConvertNapiValueToJsVal(context);
1146     info.SetReturnValue(jsVal);
1147 }
1148 
JSGetUniqueId(const JSCallbackInfo & info)1149 void JSViewPartialUpdate::JSGetUniqueId(const JSCallbackInfo& info)
1150 {
1151     auto node = AceType::DynamicCast<NG::UINode>(this->GetViewNode());
1152     auto nodeId = -1;
1153     if (node) {
1154         nodeId = node->GetId();
1155     }
1156 
1157     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(nodeId)));
1158 }
1159 
JSSendStateInfo(const std::string & stateInfo)1160 void JSViewPartialUpdate::JSSendStateInfo(const std::string& stateInfo)
1161 {
1162 #if defined(PREVIEW) || !defined(OHOS_PLATFORM)
1163     return;
1164 #else
1165     if (!LayoutInspector::GetStateProfilerStatus()) {
1166         return;
1167     }
1168     ContainerScope scope(GetInstanceId());
1169     auto node = AceType::DynamicCast<NG::UINode>(this->GetViewNode());
1170     CHECK_NULL_VOID(node);
1171     auto pipeline = node->GetContext();
1172     CHECK_NULL_VOID(pipeline);
1173 
1174     auto info = JsonUtil::ParseJsonString(stateInfo);
1175     info->Put("timeStamp", GetCurrentTimestampMicroSecond());
1176     info->Put("vsyncID", (int32_t)pipeline->GetFrameCount());
1177     info->Put("processID", getpid());
1178     info->Put("windowID", (int32_t)pipeline->GetWindowId());
1179     TAG_LOGD(AceLogTag::ACE_STATE_MGMT, "ArkUI SendStateInfo %{public}s", info->ToString().c_str());
1180     LayoutInspector::SendMessage(info->ToString());
1181 #endif
1182 }
1183 
JSSetIsV2(const bool isV2)1184 void JSViewPartialUpdate::JSSetIsV2(const bool isV2)
1185 {
1186     isV2_ = isV2;
1187 }
1188 
GetDialogController(napi_env env)1189 napi_value GetDialogController(napi_env env)
1190 {
1191     napi_value globalValue = nullptr;
1192     napi_get_global(env, &globalValue);
1193     CHECK_NULL_RETURN(globalValue, nullptr);
1194     napi_value func = nullptr;
1195     napi_get_named_property(env, globalValue, "requireNapi", &func);
1196     CHECK_NULL_RETURN(func, nullptr);
1197     napi_value module = nullptr;
1198     napi_create_string_utf8(env, "promptAction", NAPI_AUTO_LENGTH, &module);
1199     CHECK_NULL_RETURN(module, nullptr);
1200     napi_value returnValue = nullptr;
1201     napi_call_function(env, globalValue, func, 1, &module, &returnValue);
1202     CHECK_NULL_RETURN(returnValue, nullptr);
1203     napi_value constructor = nullptr;
1204     napi_get_named_property(env, returnValue, "DialogController", &constructor);
1205     CHECK_NULL_RETURN(constructor, nullptr);
1206     napi_value result = nullptr;
1207     napi_new_instance(env, constructor, 0, nullptr, &result);
1208     CHECK_NULL_RETURN(result, nullptr);
1209     return result;
1210 }
1211 
JSGetDialogController(const JSCallbackInfo & info)1212 void JSViewPartialUpdate::JSGetDialogController(const JSCallbackInfo& info)
1213 {
1214     ContainerScope scope(GetInstanceId());
1215     auto node = AceType::DynamicCast<NG::UINode>(this->GetViewNode());
1216     CHECK_NULL_VOID(node);
1217     RefPtr<NG::FrameNode> dialogNode = node->GetParentFrameNode();
1218     while (dialogNode) {
1219         if (dialogNode->GetTag() == V2::DIALOG_ETS_TAG) {
1220             break;
1221         }
1222         dialogNode = dialogNode->GetParentFrameNode();
1223     }
1224     CHECK_NULL_VOID(dialogNode);
1225 
1226     auto engine = EngineHelper::GetCurrentEngine();
1227     CHECK_NULL_VOID(engine);
1228     NativeEngine* nativeEngine = engine->GetNativeEngine();
1229     CHECK_NULL_VOID(nativeEngine);
1230     auto env = reinterpret_cast<napi_env>(nativeEngine);
1231 
1232     napi_value result = GetDialogController(env);
1233     CHECK_NULL_VOID(result);
1234     Napi::PromptDialogController* controller = nullptr;
1235     napi_unwrap(env, result, (void**)&controller);
1236     CHECK_NULL_VOID(controller);
1237     controller->SetNode(dialogNode);
1238     auto jsVal = JsConverter::ConvertNapiValueToJsVal(result);
1239     info.SetReturnValue(jsVal);
1240 }
1241 
JSBind(BindingTarget object)1242 void JSViewPartialUpdate::JSBind(BindingTarget object)
1243 {
1244     JSClass<JSViewPartialUpdate>::Declare("NativeViewPartialUpdate");
1245     MethodOptions opt = MethodOptions::NONE;
1246 
1247     JSClass<JSViewPartialUpdate>::StaticMethod("create", &JSViewPartialUpdate::Create, opt);
1248     JSClass<JSViewPartialUpdate>::StaticMethod("createRecycle", &JSViewPartialUpdate::CreateRecycle, opt);
1249     JSClass<JSViewPartialUpdate>::Method("markNeedUpdate", &JSViewPartialUpdate::MarkNeedUpdate);
1250     JSClass<JSViewPartialUpdate>::Method("syncInstanceId", &JSViewPartialUpdate::SyncInstanceId);
1251     JSClass<JSViewPartialUpdate>::Method("restoreInstanceId", &JSViewPartialUpdate::RestoreInstanceId);
1252     JSClass<JSViewPartialUpdate>::CustomMethod("getInstanceId", &JSViewPartialUpdate::GetInstanceId);
1253     JSClass<JSViewPartialUpdate>::Method("markStatic", &JSViewPartialUpdate::MarkStatic);
1254     JSClass<JSViewPartialUpdate>::Method("finishUpdateFunc", &JSViewPartialUpdate::JsFinishUpdateFunc);
1255     JSClass<JSViewPartialUpdate>::Method("setCardId", &JSViewPartialUpdate::JsSetCardId);
1256     JSClass<JSViewPartialUpdate>::CustomMethod("getCardId", &JSViewPartialUpdate::JsGetCardId);
1257     JSClass<JSViewPartialUpdate>::Method("elmtIdExists", &JSViewPartialUpdate::JsElementIdExists);
1258     JSClass<JSViewPartialUpdate>::CustomMethod("isLazyItemRender", &JSViewPartialUpdate::JSGetProxiedItemRenderState);
1259     JSClass<JSViewPartialUpdate>::CustomMethod("isFirstRender", &JSViewPartialUpdate::IsFirstRender);
1260     JSClass<JSViewPartialUpdate>::CustomMethod(
1261         "findChildByIdForPreview", &JSViewPartialUpdate::FindChildByIdForPreview);
1262     JSClass<JSViewPartialUpdate>::CustomMethod(
1263         "resetRecycleCustomNode", &JSViewPartialUpdate::JSResetRecycleCustomNode);
1264     JSClass<JSViewPartialUpdate>::CustomMethod(
1265         "queryNavDestinationInfo", &JSViewPartialUpdate::JSGetNavDestinationInfo);
1266     JSClass<JSViewPartialUpdate>::CustomMethod(
1267         "queryNavigationInfo", &JSViewPartialUpdate::JSGetNavigationInfo);
1268     JSClass<JSViewPartialUpdate>::CustomMethod(
1269         "queryRouterPageInfo", &JSViewPartialUpdate::JSGetRouterPageInfo);
1270     JSClass<JSViewPartialUpdate>::CustomMethod("getUIContext", &JSViewPartialUpdate::JSGetUIContext);
1271     JSClass<JSViewPartialUpdate>::Method("sendStateInfo", &JSViewPartialUpdate::JSSendStateInfo);
1272     JSClass<JSViewPartialUpdate>::CustomMethod("getUniqueId", &JSViewPartialUpdate::JSGetUniqueId);
1273     JSClass<JSViewPartialUpdate>::Method("setIsV2", &JSViewPartialUpdate::JSSetIsV2);
1274     JSClass<JSViewPartialUpdate>::CustomMethod("getDialogController", &JSViewPartialUpdate::JSGetDialogController);
1275     JSClass<JSViewPartialUpdate>::Method(
1276         "allowReusableV2Descendant", &JSViewPartialUpdate::JSAllowReusableV2Descendant);
1277     JSClass<JSViewPartialUpdate>::InheritAndBind<JSViewAbstract>(object, ConstructorCallback, DestructorCallback);
1278 }
1279 
JSAllowReusableV2Descendant()1280 bool JSViewPartialUpdate::JSAllowReusableV2Descendant()
1281 {
1282     return ViewPartialUpdateModel::GetInstance()->AllowReusableV2Descendant(viewNode_);
1283 }
1284 
ConstructorCallback(const JSCallbackInfo & info)1285 void JSViewPartialUpdate::ConstructorCallback(const JSCallbackInfo& info)
1286 {
1287     if (info.Length() < 1 || !info[0]->IsObject()) {
1288         LOGE("NativeViewPartialUpdate argument invalid");
1289         return;
1290     }
1291     JSRef<JSObject> thisObj = JSRef<JSObject>::Cast(info[0]);
1292 
1293     // Get js view name by this.constructor.name
1294     JSRef<JSObject> constructor = thisObj->GetProperty("constructor");
1295     JSRef<JSVal> jsViewName = constructor->GetProperty("name");
1296     auto viewName = jsViewName->ToString();
1297     auto* instance = new JSViewPartialUpdate(thisObj);
1298 
1299     auto context = info.GetExecutionContext();
1300     instance->SetContext(context);
1301     instance->SetJSViewName(viewName);
1302 
1303     //  The JS object owns the C++ object:
1304     // make sure the C++ is not destroyed when RefPtr thisObj goes out of scope
1305     // JSView::DestructorCallback has view->DecRefCount()
1306     instance->IncRefCount();
1307 
1308     info.SetReturnValue(instance);
1309 }
1310 
DestructorCallback(JSViewPartialUpdate * view)1311 void JSViewPartialUpdate::DestructorCallback(JSViewPartialUpdate* view)
1312 {
1313     if (view == nullptr) {
1314         return;
1315     }
1316     view->DecRefCount();
1317 }
1318 
1319 // ===========================================================
1320 // partial update own functions start below
1321 // ===========================================================
1322 
JsFinishUpdateFunc(int32_t elmtId)1323 void JSViewPartialUpdate::JsFinishUpdateFunc(int32_t elmtId)
1324 {
1325     ViewPartialUpdateModel::GetInstance()->FinishUpdate(
1326         viewNode_, elmtId, [weak = AceType::WeakClaim(this)](const UpdateTask& task) {
1327             auto jsView = weak.Upgrade();
1328             if (jsView) {
1329                 jsView->pendingUpdateTasks_.push_back(task);
1330             }
1331         });
1332 }
1333 
JsElementIdExists(int32_t elmtId)1334 bool JSViewPartialUpdate::JsElementIdExists(int32_t elmtId)
1335 {
1336     return ElementRegister::GetInstance()->Exists(elmtId);
1337 }
1338 
JSGetProxiedItemRenderState(const JSCallbackInfo & info)1339 void JSViewPartialUpdate::JSGetProxiedItemRenderState(const JSCallbackInfo& info)
1340 {
1341     if (info.Length() != 1 || !info[0]->IsNumber()) {
1342         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
1343         return;
1344     }
1345     const auto elmtId = info[0]->ToNumber<int32_t>();
1346 
1347     if (elmtId == ElementRegister::UndefinedElementId) {
1348         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
1349         return;
1350     }
1351     auto result = false;
1352 
1353     // set boolean return value to JS
1354     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
1355 }
1356 
IsFirstRender(const JSCallbackInfo & info)1357 void JSViewPartialUpdate::IsFirstRender(const JSCallbackInfo& info)
1358 {
1359     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(isFirstRender_)));
1360 }
1361 
FindChildByIdForPreview(const JSCallbackInfo & info)1362 void JSViewPartialUpdate::FindChildByIdForPreview(const JSCallbackInfo& info)
1363 {
1364     if (!info[0]->IsNumber()) {
1365         return;
1366     }
1367     std::string viewId = std::to_string(info[0]->ToNumber<int32_t>());
1368     JSRef<JSObject> targetView = Framework::JSViewStackProcessor::GetViewById(viewId);
1369     info.SetReturnValue(targetView);
1370     return;
1371 }
1372 
1373 } // namespace OHOS::Ace::Framework
1374