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