• 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_view_stack_processor.h"
30 #include "bridge/declarative_frontend/jsview/models/view_full_update_model_impl.h"
31 #include "bridge/declarative_frontend/jsview/models/view_partial_update_model_impl.h"
32 #include "bridge/declarative_frontend/ng/declarative_frontend_ng.h"
33 #include "core/common/container.h"
34 #include "core/common/container_scope.h"
35 #include "core/components_ng/base/observer_handler.h"
36 #include "core/components_ng/base/ui_node.h"
37 #include "core/components_ng/base/view_full_update_model.h"
38 #include "core/components_ng/base/view_full_update_model_ng.h"
39 #include "core/components_ng/base/view_partial_update_model.h"
40 #include "core/components_ng/base/view_partial_update_model_ng.h"
41 #include "core/components_ng/base/view_stack_model.h"
42 #include "core/components_ng/layout/layout_wrapper.h"
43 #include "core/components_ng/pattern/custom/custom_measure_layout_node.h"
44 #include "core/pipeline/base/element_register.h"
45 
46 namespace OHOS::Ace {
47 
48 std::unique_ptr<ViewFullUpdateModel> ViewFullUpdateModel::instance_ = nullptr;
49 std::mutex ViewFullUpdateModel::mutex_;
50 std::unique_ptr<ViewPartialUpdateModel> ViewPartialUpdateModel::instance_ = nullptr;
51 std::mutex ViewPartialUpdateModel::mutex_;
52 
GetInstance()53 ViewFullUpdateModel* ViewFullUpdateModel::GetInstance()
54 {
55     if (!instance_) {
56         std::lock_guard<std::mutex> lock(mutex_);
57         if (!instance_) {
58 #ifdef NG_BUILD
59             instance_.reset(new NG::ViewFullUpdateModelNG());
60 #else
61             if (Container::IsCurrentUseNewPipeline()) {
62                 instance_.reset(new NG::ViewFullUpdateModelNG());
63             } else {
64                 instance_.reset(new Framework::ViewFullUpdateModelImpl());
65             }
66 #endif
67         }
68     }
69     return instance_.get();
70 }
71 
GetInstance()72 ViewPartialUpdateModel* ViewPartialUpdateModel::GetInstance()
73 {
74     if (!instance_) {
75         std::lock_guard<std::mutex> lock(mutex_);
76         if (!instance_) {
77 #ifdef NG_BUILD
78             instance_.reset(new NG::ViewPartialUpdateModelNG());
79 #else
80             if (Container::IsCurrentUseNewPipeline()) {
81                 instance_.reset(new NG::ViewPartialUpdateModelNG());
82             } else {
83                 instance_.reset(new Framework::ViewPartialUpdateModelImpl());
84             }
85 #endif
86         }
87     }
88     return instance_.get();
89 }
90 
91 } // namespace OHOS::Ace
92 
93 namespace OHOS::Ace::Framework {
94 
JSBind(BindingTarget object)95 void JSView::JSBind(BindingTarget object)
96 {
97     JSViewPartialUpdate::JSBind(object);
98     JSViewFullUpdate::JSBind(object);
99 }
100 
RenderJSExecution()101 void JSView::RenderJSExecution()
102 {
103     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
104     if (!jsViewFunction_) {
105         return;
106     }
107     {
108         ACE_SCORING_EVENT("Component.AboutToRender");
109         jsViewFunction_->ExecuteAboutToRender();
110     }
111     if (!jsViewFunction_) {
112         return;
113     }
114     {
115         ACE_SCORING_EVENT("Component.Build");
116         ViewStackModel::GetInstance()->PushKey(viewId_);
117         jsViewFunction_->ExecuteRender();
118         ViewStackModel::GetInstance()->PopKey();
119     }
120     if (!jsViewFunction_) {
121         return;
122     }
123     {
124         ACE_SCORING_EVENT("Component.OnRenderDone");
125         jsViewFunction_->ExecuteOnRenderDone();
126         if (notifyRenderDone_) {
127             notifyRenderDone_();
128         }
129     }
130 }
131 
SyncInstanceId()132 void JSView::SyncInstanceId()
133 {
134     restoreInstanceIdStack_.push(Container::CurrentId());
135     ContainerScope::UpdateCurrent(instanceId_);
136 }
137 
RestoreInstanceId()138 void JSView::RestoreInstanceId()
139 {
140     if (restoreInstanceIdStack_.empty()) {
141         ContainerScope::UpdateCurrent(-1);
142         return;
143     }
144     ContainerScope::UpdateCurrent(restoreInstanceIdStack_.top());
145     restoreInstanceIdStack_.pop();
146 }
147 
GetInstanceId(const JSCallbackInfo & info)148 void JSView::GetInstanceId(const JSCallbackInfo& info)
149 {
150     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(instanceId_)));
151 }
152 
JsSetCardId(int64_t cardId)153 void JSView::JsSetCardId(int64_t cardId)
154 {
155     cardId_ = cardId;
156 }
157 
JsGetCardId(const JSCallbackInfo & info)158 void JSView::JsGetCardId(const JSCallbackInfo& info)
159 {
160     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(cardId_)));
161 }
162 
JSViewFullUpdate(const std::string & viewId,JSRef<JSObject> jsObject,JSRef<JSFunc> jsRenderFunction)163 JSViewFullUpdate::JSViewFullUpdate(const std::string& viewId, JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction)
164 {
165     viewId_ = viewId;
166     jsViewFunction_ = AceType::MakeRefPtr<ViewFunctions>(jsObject, jsRenderFunction);
167     jsViewObject_ = jsObject;
168 }
169 
~JSViewFullUpdate()170 JSViewFullUpdate::~JSViewFullUpdate()
171 {
172     jsViewFunction_.Reset();
173 };
174 
CreateViewNode(bool isTitleNode)175 RefPtr<AceType> JSViewFullUpdate::CreateViewNode(bool isTitleNode)
176 {
177     auto appearFunc = [weak = AceType::WeakClaim(this)] {
178         auto jsView = weak.Upgrade();
179         CHECK_NULL_VOID(jsView);
180         ContainerScope scope(jsView->GetInstanceId());
181         ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Appear");
182         if (jsView->viewNode_.Invalid() && jsView->jsViewFunction_) {
183             jsView->jsViewFunction_->ExecuteAppear();
184         }
185     };
186 
187     auto renderFunction = [weak = AceType::WeakClaim(this)]() -> RefPtr<AceType> {
188         auto jsView = weak.Upgrade();
189         CHECK_NULL_RETURN(jsView, nullptr);
190         ContainerScope scope(jsView->GetInstanceId());
191         return jsView->InternalRender();
192     };
193 
194     auto pageTransitionFunction = [weak = AceType::WeakClaim(this)]() {
195         auto jsView = weak.Upgrade();
196         if (!jsView || !jsView->jsViewFunction_) {
197             return;
198         }
199         {
200             ContainerScope scope(jsView->GetInstanceId());
201             ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Transition");
202             jsView->jsViewFunction_->ExecuteTransition();
203         }
204     };
205 
206     auto updateViewNodeFunction = [weak = AceType::WeakClaim(this)](const RefPtr<AceType>& node) {
207         auto jsView = weak.Upgrade();
208         if (jsView) {
209             jsView->viewNode_ = node;
210         }
211     };
212 
213     auto removeFunction = [weak = AceType::WeakClaim(this)]() -> void {
214         auto jsView = weak.Upgrade();
215         if (jsView && jsView->jsViewFunction_) {
216             ContainerScope scope(jsView->GetInstanceId());
217             jsView->jsViewFunction_->ExecuteDisappear();
218         }
219     };
220 
221     NodeInfo info = { .viewId = viewId_,
222         .appearFunc = std::move(appearFunc),
223         .renderFunc = std::move(renderFunction),
224         .removeFunc = std::move(removeFunction),
225         .updateNodeFunc = std::move(updateViewNodeFunction),
226         .isStatic = IsStatic() };
227 
228     if (jsViewFunction_ && jsViewFunction_->HasPageTransition()) {
229         info.pageTransitionFunc = std::move(pageTransitionFunction);
230     }
231 
232     return ViewFullUpdateModel::GetInstance()->CreateNode(std::move(info));
233 }
234 
InternalRender()235 RefPtr<AceType> JSViewFullUpdate::InternalRender()
236 {
237     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
238     needsUpdate_ = false;
239     RenderJSExecution();
240     CleanUpAbandonedChild();
241     jsViewFunction_->Destroy();
242     return ViewStackModel::GetInstance()->Finish();
243 }
244 
245 /**
246  * marks the JSView's composed component as needing update / rerender
247  */
MarkNeedUpdate()248 void JSViewFullUpdate::MarkNeedUpdate()
249 {
250     ACE_SCOPED_TRACE("JSView::MarkNeedUpdate");
251     needsUpdate_ = ViewFullUpdateModel::GetInstance()->MarkNeedUpdate(viewNode_);
252 }
253 
Destroy(JSView * parentCustomView)254 void JSViewFullUpdate::Destroy(JSView* parentCustomView)
255 {
256     DestroyChild(parentCustomView);
257     {
258         ACE_SCORING_EVENT("Component[" + viewId_ + "].Disappear");
259         jsViewFunction_->ExecuteDisappear();
260     }
261     {
262         ACE_SCORING_EVENT("Component[" + viewId_ + "].AboutToBeDeleted");
263         jsViewFunction_->ExecuteAboutToBeDeleted();
264     }
265     jsViewObject_.Reset();
266 }
267 
Create(const JSCallbackInfo & info)268 void JSViewFullUpdate::Create(const JSCallbackInfo& info)
269 {
270     ACE_DCHECK(!Container::IsCurrentUsePartialUpdate());
271 
272     if (info[0]->IsObject()) {
273         JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
274         auto* view = object->Unwrap<JSViewFullUpdate>();
275         if (view == nullptr) {
276             return;
277         }
278         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
279     }
280 }
281 
JSBind(BindingTarget object)282 void JSViewFullUpdate::JSBind(BindingTarget object)
283 {
284     JSClass<JSViewFullUpdate>::Declare("NativeViewFullUpdate");
285     JSClass<JSViewFullUpdate>::StaticMethod("create", &JSViewFullUpdate::Create);
286     JSClass<JSViewFullUpdate>::Method("markNeedUpdate", &JSViewFullUpdate::MarkNeedUpdate);
287     JSClass<JSViewFullUpdate>::Method("syncInstanceId", &JSViewFullUpdate::SyncInstanceId);
288     JSClass<JSViewFullUpdate>::Method("restoreInstanceId", &JSViewFullUpdate::RestoreInstanceId);
289     JSClass<JSViewFullUpdate>::CustomMethod("getInstanceId", &JSViewFullUpdate::GetInstanceId);
290     JSClass<JSViewFullUpdate>::Method("needsUpdate", &JSViewFullUpdate::NeedsUpdate);
291     JSClass<JSViewFullUpdate>::Method("markStatic", &JSViewFullUpdate::MarkStatic);
292     JSClass<JSViewFullUpdate>::Method("setCardId", &JSViewFullUpdate::JsSetCardId);
293     JSClass<JSViewFullUpdate>::CustomMethod("getCardId", &JSViewFullUpdate::JsGetCardId);
294     JSClass<JSViewFullUpdate>::CustomMethod("findChildById", &JSViewFullUpdate::FindChildById);
295     JSClass<JSViewFullUpdate>::CustomMethod("findChildByIdForPreview", &JSViewFullUpdate::FindChildByIdForPreview);
296     JSClass<JSViewFullUpdate>::InheritAndBind<JSViewAbstract>(object, ConstructorCallback, DestructorCallback);
297 }
298 
FindChildById(const JSCallbackInfo & info)299 void JSViewFullUpdate::FindChildById(const JSCallbackInfo& info)
300 {
301     if (info[0]->IsNumber() || info[0]->IsString()) {
302         std::string viewId = info[0]->ToString();
303         info.SetReturnValue(GetChildById(viewId));
304     } else {
305         JSException::Throw("%s", "JSView FindChildById with invalid arguments.");
306     }
307 }
308 
FindChildByIdForPreview(const JSCallbackInfo & info)309 void JSViewFullUpdate::FindChildByIdForPreview(const JSCallbackInfo& info)
310 {
311     if (!info[0]->IsNumber()) {
312         return;
313     }
314     std::string viewId = std::to_string(info[0]->ToNumber<int32_t>());
315     if (viewId_ == viewId) {
316         info.SetReturnValue(jsViewObject_);
317         return;
318     }
319     JSRef<JSObject> targetView = JSRef<JSObject>::New();
320     for (auto&& child : customViewChildren_) {
321         if (GetChildByViewId(viewId, child.second, targetView)) {
322             break;
323         }
324     }
325     auto view = targetView->Unwrap<JSViewFullUpdate>();
326     if (view) {
327         info.SetReturnValue(targetView);
328     }
329     return;
330 }
331 
GetChildByViewId(const std::string & viewId,JSRef<JSObject> & childView,JSRef<JSObject> & targetView)332 bool JSViewFullUpdate::GetChildByViewId(
333     const std::string& viewId, JSRef<JSObject>& childView, JSRef<JSObject>& targetView)
334 {
335     auto* view = childView->Unwrap<JSViewFullUpdate>();
336     if (view && view->viewId_ == viewId) {
337         targetView = childView;
338         return true;
339     }
340     for (auto&& child : view->customViewChildren_) {
341         if (GetChildByViewId(viewId, child.second, targetView)) {
342             return true;
343         }
344     }
345     return false;
346 }
347 
ConstructorCallback(const JSCallbackInfo & info)348 void JSViewFullUpdate::ConstructorCallback(const JSCallbackInfo& info)
349 {
350     JSRef<JSObject> thisObj = info.This();
351     JSRef<JSVal> renderFunc = thisObj->GetProperty("render");
352     if (!renderFunc->IsFunction()) {
353         JSException::Throw("%s", "View derived classes must provide render(){...} function");
354         return;
355     }
356 
357     int argc = info.Length();
358     if (argc > 1 && (info[0]->IsNumber() || info[0]->IsString())) {
359         std::string viewId = info[0]->ToString();
360         auto instance = AceType::MakeRefPtr<JSViewFullUpdate>(viewId, info.This(), JSRef<JSFunc>::Cast(renderFunc));
361         auto context = info.GetExecutionContext();
362         instance->SetContext(context);
363         instance->IncRefCount();
364         info.SetReturnValue(AceType::RawPtr(instance));
365         if (!info[1]->IsUndefined() && info[1]->IsObject()) {
366             JSRef<JSObject> parentObj = JSRef<JSObject>::Cast(info[1]);
367             auto* parentView = parentObj->Unwrap<JSViewFullUpdate>();
368             if (parentView != nullptr) {
369                 auto id = parentView->AddChildById(viewId, info.This());
370                 instance->id_ = id;
371             }
372         }
373     } else {
374         JSException::Throw("%s", "JSView creation with invalid arguments.");
375     }
376 }
377 
DestructorCallback(JSViewFullUpdate * view)378 void JSViewFullUpdate::DestructorCallback(JSViewFullUpdate* view)
379 {
380     if (view == nullptr) {
381         return;
382     }
383     view->DecRefCount();
384 }
385 
DestroyChild(JSView * parentCustomView)386 void JSViewFullUpdate::DestroyChild(JSView* parentCustomView)
387 {
388     for (auto&& child : customViewChildren_) {
389         auto* view = child.second->Unwrap<JSView>();
390         if (view != nullptr) {
391             view->Destroy(this);
392         }
393         child.second.Reset();
394     }
395     customViewChildren_.clear();
396     for (auto&& lazyChild : customViewChildrenWithLazy_) {
397         auto* view = lazyChild.second->Unwrap<JSView>();
398         if (view != nullptr) {
399             view->Destroy(this);
400         }
401         lazyChild.second.Reset();
402     }
403     customViewChildrenWithLazy_.clear();
404 }
405 
CleanUpAbandonedChild()406 void JSViewFullUpdate::CleanUpAbandonedChild()
407 {
408     auto startIter = customViewChildren_.begin();
409     auto endIter = customViewChildren_.end();
410     std::vector<std::string> removedViewIds;
411     while (startIter != endIter) {
412         auto found = lastAccessedViewIds_.find(startIter->first);
413         if (found == lastAccessedViewIds_.end()) {
414             removedViewIds.emplace_back(startIter->first);
415             auto* view = startIter->second->Unwrap<JSView>();
416             if (view != nullptr) {
417                 view->Destroy(this);
418             }
419             startIter->second.Reset();
420         }
421         ++startIter;
422     }
423 
424     for (auto& viewId : removedViewIds) {
425         customViewChildren_.erase(viewId);
426     }
427 
428     lastAccessedViewIds_.clear();
429 }
430 
GetChildById(const std::string & viewId)431 JSRef<JSObject> JSViewFullUpdate::GetChildById(const std::string& viewId)
432 {
433     std::string id = ViewStackModel::GetInstance()->ProcessViewId(viewId);
434     auto found = customViewChildren_.find(id);
435     if (found != customViewChildren_.end()) {
436         ChildAccessedById(id);
437         return found->second;
438     }
439     auto lazyItem = customViewChildrenWithLazy_.find(id);
440     if (lazyItem != customViewChildrenWithLazy_.end()) {
441         return lazyItem->second;
442     }
443     return {};
444 }
445 
AddChildById(const std::string & viewId,const JSRef<JSObject> & obj)446 std::string JSViewFullUpdate::AddChildById(const std::string& viewId, const JSRef<JSObject>& obj)
447 {
448     std::string id = ViewStackModel::GetInstance()->ProcessViewId(viewId);
449     JSView* jsView = nullptr;
450     if (isLazyForEachProcessed_) {
451         auto result = customViewChildrenWithLazy_.try_emplace(id, obj);
452         if (!result.second) {
453             jsView = result.first->second->Unwrap<JSView>();
454             result.first->second = obj;
455         } else {
456             lazyItemGroups_[lazyItemGroupId_].emplace_back(id);
457         }
458     } else {
459         auto result = customViewChildren_.try_emplace(id, obj);
460         if (!result.second) {
461             jsView = result.first->second->Unwrap<JSView>();
462             result.first->second = obj;
463         }
464         ChildAccessedById(id);
465     }
466     if (jsView != nullptr) {
467         jsView->Destroy(this);
468     }
469     return id;
470 }
471 
RemoveChildGroupById(const std::string & viewId)472 void JSViewFullUpdate::RemoveChildGroupById(const std::string& viewId)
473 {
474     // js runtime may be released
475     CHECK_JAVASCRIPT_SCOPE_AND_RETURN;
476     JAVASCRIPT_EXECUTION_SCOPE_STATIC;
477     auto iter = lazyItemGroups_.find(viewId);
478     if (iter == lazyItemGroups_.end()) {
479         return;
480     }
481     std::vector<std::string> removedViewIds;
482     for (auto&& item : iter->second) {
483         auto removeView = customViewChildrenWithLazy_.find(item);
484         if (removeView != customViewChildrenWithLazy_.end()) {
485             if (!removeView->second.IsEmpty()) {
486                 auto* view = removeView->second->Unwrap<JSView>();
487                 if (view != nullptr) {
488                     view->Destroy(this);
489                 }
490                 removeView->second.Reset();
491             }
492             removedViewIds.emplace_back(item);
493         }
494     }
495 
496     for (auto&& removeId : removedViewIds) {
497         customViewChildrenWithLazy_.erase(removeId);
498     }
499     lazyItemGroups_.erase(iter);
500 }
501 
ChildAccessedById(const std::string & viewId)502 void JSViewFullUpdate::ChildAccessedById(const std::string& viewId)
503 {
504     lastAccessedViewIds_.emplace(viewId);
505 }
506 
507 // =================================================================
508 
509 std::map<std::string, JSRef<JSObject>> JSViewStackProcessor::viewMap_;
510 
JSViewPartialUpdate(JSRef<JSObject> jsViewObject)511 JSViewPartialUpdate::JSViewPartialUpdate(JSRef<JSObject> jsViewObject)
512 {
513     jsViewFunction_ = AceType::MakeRefPtr<ViewFunctions>(jsViewObject);
514     // keep the reference to the JS View object to prevent GC
515     jsViewObject_ = jsViewObject;
516 }
517 
~JSViewPartialUpdate()518 JSViewPartialUpdate::~JSViewPartialUpdate()
519 {
520     jsViewFunction_.Reset();
521 };
522 
CreateViewNode(bool isTitleNode)523 RefPtr<AceType> JSViewPartialUpdate::CreateViewNode(bool isTitleNode)
524 {
525     auto updateViewIdFunc = [weak = AceType::WeakClaim(this)](const std::string viewId) {
526         auto jsView = weak.Upgrade();
527         CHECK_NULL_VOID(jsView);
528         jsView->viewId_ = viewId;
529     };
530 
531     auto appearFunc = [weak = AceType::WeakClaim(this)]() {
532         auto jsView = weak.Upgrade();
533         CHECK_NULL_VOID(jsView);
534         ContainerScope scope(jsView->GetInstanceId());
535         ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Appear");
536         if (jsView->jsViewFunction_) {
537             jsView->jsViewFunction_->ExecuteAppear();
538         }
539     };
540 
541     auto renderFunction = [weak = AceType::WeakClaim(this)]() -> RefPtr<AceType> {
542         auto jsView = weak.Upgrade();
543         CHECK_NULL_RETURN(jsView, nullptr);
544         ContainerScope scope(jsView->GetInstanceId());
545         if (!jsView->isFirstRender_) {
546             return nullptr;
547         }
548         jsView->isFirstRender_ = false;
549         return jsView->InitialRender();
550     };
551 
552     auto updateFunction = [weak = AceType::WeakClaim(this)]() -> void {
553         auto jsView = weak.Upgrade();
554         CHECK_NULL_VOID(jsView);
555         ContainerScope scope(jsView->GetInstanceId());
556         if (!jsView->needsUpdate_) {
557             return;
558         }
559         jsView->needsUpdate_ = false;
560         {
561             ACE_SCOPED_TRACE("JSView: ExecuteRerender");
562             jsView->jsViewFunction_->ExecuteRerender();
563         }
564         for (const UpdateTask& updateTask : jsView->pendingUpdateTasks_) {
565             ViewPartialUpdateModel::GetInstance()->FlushUpdateTask(updateTask);
566         }
567         jsView->pendingUpdateTasks_.clear();
568     };
569 
570     auto reloadFunction = [weak = AceType::WeakClaim(this)](bool deep) {
571         auto jsView = weak.Upgrade();
572         CHECK_NULL_VOID(jsView);
573         CHECK_NULL_VOID(jsView->jsViewFunction_);
574         ContainerScope scope(jsView->GetInstanceId());
575         jsView->jsViewFunction_->ExecuteReload(deep);
576     };
577 
578     // @Component level complete reload, can detect added/deleted frame nodes
579     auto completeReloadFunc = [weak = AceType::WeakClaim(this)]() -> RefPtr<AceType> {
580         auto jsView = weak.Upgrade();
581         CHECK_NULL_RETURN(jsView, nullptr);
582         ContainerScope scope(jsView->GetInstanceId());
583         return jsView->InitialRender();
584     };
585 
586     auto pageTransitionFunction = [weak = AceType::WeakClaim(this)]() {
587         auto jsView = weak.Upgrade();
588         CHECK_NULL_VOID(jsView);
589         CHECK_NULL_VOID(jsView->jsViewFunction_);
590         ContainerScope scope(jsView->GetInstanceId());
591         {
592             ACE_SCORING_EVENT("Component[" + jsView->viewId_ + "].Transition");
593             jsView->jsViewFunction_->ExecuteTransition();
594         }
595     };
596 
597     auto removeFunction = [weak = AceType::WeakClaim(this)]() -> void {
598         auto jsView = weak.Upgrade();
599         CHECK_NULL_VOID(jsView);
600         ContainerScope scope(jsView->GetInstanceId());
601         jsView->Destroy(nullptr);
602         jsView->viewNode_.Reset();
603     };
604 
605     auto updateViewNodeFunction = [weak = AceType::WeakClaim(this)](const RefPtr<AceType>& node) {
606         auto jsView = weak.Upgrade();
607         CHECK_NULL_VOID(jsView);
608         jsView->viewNode_ = node;
609     };
610 
611     auto nodeUpdateFunc = [weak = AceType::WeakClaim(this)](int32_t nodeId) {
612         auto jsView = weak.Upgrade();
613         CHECK_NULL_VOID(jsView);
614         CHECK_NULL_VOID(jsView->jsViewFunction_);
615         ContainerScope scope(jsView->GetInstanceId());
616         jsView->jsViewFunction_->ExecuteForceNodeRerender(nodeId);
617     };
618 
619     auto recycleCustomNode = [weak = AceType::WeakClaim(this)](const RefPtr<NG::CustomNodeBase>& recycleNode) -> void {
620         auto jsView = weak.Upgrade();
621         CHECK_NULL_VOID(jsView);
622         ContainerScope scope(jsView->GetInstanceId());
623         auto name = jsView->GetRecycleCustomNodeName();
624         if (name.empty()) {
625             return;
626         }
627         AceType::DynamicCast<NG::UINode>(recycleNode)->SetActive(false);
628         jsView->SetRecycleCustomNode(recycleNode);
629         if (!recycleNode->HasRecycleRenderFunc()) {
630             jsView->jsViewFunction_->ExecuteAboutToRecycle();
631         }
632         recycleNode->ResetRecycle();
633         jsView->jsViewFunction_->ExecuteRecycle(jsView->GetRecycleCustomNodeName());
634     };
635 
636     auto setActiveFunc = [weak = AceType::WeakClaim(this)](bool active) -> void {
637         auto jsView = weak.Upgrade();
638         CHECK_NULL_VOID(jsView);
639         ContainerScope scope(jsView->GetInstanceId());
640         jsView->jsViewFunction_->ExecuteSetActive(active);
641     };
642 
643     auto onDumpInfoFunc = [weak = AceType::WeakClaim(this)](const std::vector<std::string>& params) -> void {
644         auto jsView = weak.Upgrade();
645         CHECK_NULL_VOID(jsView);
646         ContainerScope scope(jsView->GetInstanceId());
647         jsView->jsViewFunction_->ExecuteOnDumpInfo(params);
648     };
649 
650     NodeInfoPU info = { .appearFunc = std::move(appearFunc),
651         .renderFunc = std::move(renderFunction),
652         .updateFunc = std::move(updateFunction),
653         .removeFunc = std::move(removeFunction),
654         .updateNodeFunc = std::move(updateViewNodeFunction),
655         .pageTransitionFunc = std::move(pageTransitionFunction),
656         .reloadFunc = std::move(reloadFunction),
657         .completeReloadFunc = std::move(completeReloadFunc),
658         .nodeUpdateFunc = std::move(nodeUpdateFunc),
659         .recycleCustomNodeFunc = recycleCustomNode,
660         .setActiveFunc = std::move(setActiveFunc),
661         .onDumpInfoFunc = std::move(onDumpInfoFunc),
662         .hasMeasureOrLayout = jsViewFunction_->HasMeasure() || jsViewFunction_->HasLayout() ||
663                               jsViewFunction_->HasMeasureSize() || jsViewFunction_->HasPlaceChildren(),
664         .isStatic = IsStatic(),
665         .jsViewName = GetJSViewName() };
666 
667     auto measureFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
668         auto jsView = weak.Upgrade();
669         CHECK_NULL_VOID(jsView);
670         ContainerScope scope(jsView->GetInstanceId());
671         jsView->jsViewFunction_->ExecuteMeasure(layoutWrapper);
672     };
673     if (jsViewFunction_->HasMeasure()) {
674         info.measureFunc = std::move(measureFunc);
675     }
676 
677     auto layoutFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
678         auto jsView = weak.Upgrade();
679         CHECK_NULL_VOID(jsView);
680         ContainerScope scope(jsView->GetInstanceId());
681         jsView->jsViewFunction_->ExecuteLayout(layoutWrapper);
682     };
683     if (jsViewFunction_->HasLayout()) {
684         info.layoutFunc = std::move(layoutFunc);
685     }
686 
687     if (jsViewFunction_->HasMeasureSize()) {
688         auto measureSizeFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
689             auto jsView = weak.Upgrade();
690             CHECK_NULL_VOID(jsView);
691             ContainerScope scope(jsView->GetInstanceId());
692             jsView->jsViewFunction_->ExecuteMeasureSize(layoutWrapper);
693         };
694         info.measureSizeFunc = std::move(measureSizeFunc);
695     }
696 
697     if (jsViewFunction_->HasPlaceChildren()) {
698         auto placeChildren = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
699             auto jsView = weak.Upgrade();
700             CHECK_NULL_VOID(jsView);
701             ContainerScope scope(jsView->GetInstanceId());
702             jsView->jsViewFunction_->ExecutePlaceChildren(layoutWrapper);
703         };
704         info.placeChildrenFunc = std::move(placeChildren);
705     }
706 
707     JSRef<JSObject> jsViewExtraInfo = jsViewObject_->GetProperty("extraInfo_");
708     if (!jsViewExtraInfo->IsUndefined()) {
709         JSRef<JSVal> jsPage = jsViewExtraInfo->GetProperty("page");
710         JSRef<JSVal> jsLine = jsViewExtraInfo->GetProperty("line");
711         info.extraInfo = {.page = jsPage->ToString(), .line = jsLine->ToNumber<int32_t>()};
712     }
713 
714     if (isTitleNode) {
715         info.isCustomTitle = true;
716     }
717 
718     auto node = ViewPartialUpdateModel::GetInstance()->CreateNode(std::move(info));
719     auto customMeasureLayoutNode = DynamicCast<NG::CustomMeasureLayoutNode>(node);
720     if (customMeasureLayoutNode) {
721         auto updateParamFunc = [weak = AceType::WeakClaim(this)](NG::LayoutWrapper* layoutWrapper) -> void {
722             auto jsView = weak.Upgrade();
723             CHECK_NULL_VOID(jsView);
724             ContainerScope scope(jsView->GetInstanceId());
725             jsView->jsViewFunction_->InitJsParam(layoutWrapper);
726         };
727         customMeasureLayoutNode->SetUpdateParamFunc(updateParamFunc);
728     }
729 #ifdef PREVIEW
730     auto uiNode = AceType::DynamicCast<NG::UINode>(node);
731     if (uiNode) {
732         Framework::JSViewStackProcessor::SetViewMap(std::to_string(uiNode->GetId()), jsViewObject_);
733     }
734 #endif
735 
736     if (AceChecker::IsPerformanceCheckEnabled()) {
737         auto uiNode = AceType::DynamicCast<NG::UINode>(node);
738         if (uiNode) {
739             auto codeInfo = EngineHelper::GetPositionOnJsCode();
740             uiNode->SetRow(codeInfo.first);
741             uiNode->SetCol(codeInfo.second);
742         }
743     }
744     return node;
745 }
746 
InitialRender()747 RefPtr<AceType> JSViewPartialUpdate::InitialRender()
748 {
749     needsUpdate_ = false;
750     RenderJSExecution();
751     return ViewStackModel::GetInstance()->Finish();
752 }
753 
754 // parentCustomView in not used by PartialUpdate
Destroy(JSView * parentCustomView)755 void JSViewPartialUpdate::Destroy(JSView* parentCustomView)
756 {
757     if (jsViewFunction_ == nullptr) {
758         // already called Destroy before
759         return;
760     }
761     {
762         ACE_SCORING_EVENT("Component[" + viewId_ + "].Disappear");
763         jsViewFunction_->ExecuteDisappear();
764     }
765     {
766         ACE_SCORING_EVENT("Component[" + viewId_ + "].AboutToBeDeleted");
767         jsViewFunction_->ExecuteAboutToBeDeleted();
768     }
769     pendingUpdateTasks_.clear();
770     jsViewFunction_->Destroy();
771     jsViewFunction_.Reset();
772 
773     // release reference to JS view object, and allow GC, calls DestructorCallback
774     jsViewObject_.Reset();
775 }
776 
MarkNeedUpdate()777 void JSViewPartialUpdate::MarkNeedUpdate()
778 {
779     needsUpdate_ = ViewPartialUpdateModel::GetInstance()->MarkNeedUpdate(viewNode_);
780 }
781 
782 /**
783  * in JS View.create(new View(...));
784  * used for FullRender case, not for re-render case
785  */
Create(const JSCallbackInfo & info)786 void JSViewPartialUpdate::Create(const JSCallbackInfo& info)
787 {
788     ACE_DCHECK(Container::IsCurrentUsePartialUpdate());
789 
790     if (info[0]->IsObject()) {
791         JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
792         auto* view = object->Unwrap<JSView>();
793         if (view == nullptr) {
794             LOGE("View is null");
795             return;
796         }
797         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
798     }
799 }
800 
801 enum {
802     PARAM_VIEW_OBJ = 0,
803     PARAM_IS_RECYCLE,
804     PARAM_NODE_NAME,
805     PARAM_RECYCLE_UPDATE_FUNC,
806 
807     PARAM_SIZE,
808 };
809 
ParseRecycleParams(const JSCallbackInfo & info,JSRef<JSVal> (& params)[PARAM_SIZE])810 bool ParseRecycleParams(const JSCallbackInfo& info, JSRef<JSVal> (&params)[PARAM_SIZE])
811 {
812     if (info.Length() != PARAM_SIZE) {
813         return false;
814     }
815     if (!info[PARAM_VIEW_OBJ]->IsObject()) {
816         return false;
817     }
818     if (!info[PARAM_IS_RECYCLE]->IsBoolean()) {
819         return false;
820     }
821     if (!info[PARAM_RECYCLE_UPDATE_FUNC]->IsFunction()) {
822         return false;
823     }
824 
825     for (int32_t idx = PARAM_VIEW_OBJ; idx < PARAM_SIZE; ++idx) {
826         params[idx] = info[idx];
827     }
828     return true;
829 }
830 
831 /**
832  * in JS ViewPU.createRecycle(...)
833  * create a recyclable custom node
834  */
CreateRecycle(const JSCallbackInfo & info)835 void JSViewPartialUpdate::CreateRecycle(const JSCallbackInfo& info)
836 {
837     ACE_DCHECK(Container::IsCurrentUsePartialUpdate());
838 
839     JSRef<JSVal> params[PARAM_SIZE];
840     if (!ParseRecycleParams(info, params)) {
841         return;
842     }
843 
844     auto viewObj = JSRef<JSObject>::Cast(params[PARAM_VIEW_OBJ]);
845     auto* view = viewObj->Unwrap<JSViewPartialUpdate>();
846     if (!view) {
847         return;
848     }
849     if (info[PARAM_NODE_NAME]->IsUndefined()) {
850         view->SetRecycleCustomNodeName("");
851         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
852         return;
853     }
854     auto recycle = params[PARAM_IS_RECYCLE]->ToBoolean();
855     auto nodeName = params[PARAM_NODE_NAME]->ToString();
856     auto jsRecycleUpdateFunc =
857         AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(params[PARAM_RECYCLE_UPDATE_FUNC]));
858     auto recycleUpdateFunc = [weak = AceType::WeakClaim(view), execCtx = info.GetExecutionContext(),
859                                  func = std::move(jsRecycleUpdateFunc)]() -> void {
860         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
861         auto jsView = weak.Upgrade();
862         CHECK_NULL_VOID(jsView);
863         jsView->SetIsRecycleRerender(true);
864         func->ExecuteJS();
865         jsView->SetIsRecycleRerender(false);
866     };
867 
868     // update view and node property
869     view->SetRecycleCustomNodeName(nodeName);
870 
871     // get or create recycle node
872     if (recycle) {
873         auto node = view->GetCachedRecycleNode();
874         node->SetRecycleRenderFunc(std::move(recycleUpdateFunc));
875         ViewStackModel::GetInstance()->Push(node, true);
876     } else {
877         ViewStackModel::GetInstance()->Push(view->CreateViewNode(), true);
878     }
879 }
880 
OnDumpInfo(const std::vector<std::string> & params)881 void JSViewPartialUpdate::OnDumpInfo(const std::vector<std::string>& params)
882 {
883     CHECK_NULL_VOID(jsViewFunction_);
884     jsViewFunction_->ExecuteOnDumpInfo(params);
885 }
886 
JSGetNavDestinationInfo(const JSCallbackInfo & info)887 void JSViewPartialUpdate::JSGetNavDestinationInfo(const JSCallbackInfo& info)
888 {
889     auto result = NG::UIObserverHandler::GetInstance().GetNavigationState(GetViewNode());
890     if (result) {
891         JSRef<JSObject> obj = JSRef<JSObject>::New();
892         obj->SetProperty<std::string>("navigationId", result->navigationId);
893         obj->SetProperty<std::string>("name", result->name);
894         obj->SetProperty<int32_t>("state", static_cast<int32_t>(result->state));
895         info.SetReturnValue(obj);
896     }
897 }
898 
JSGetUIContext(const JSCallbackInfo & info)899 void JSViewPartialUpdate::JSGetUIContext(const JSCallbackInfo& info)
900 {
901     ContainerScope scope(GetInstanceId());
902     auto container = Container::Current();
903     CHECK_NULL_VOID(container);
904     auto frontend = container->GetFrontend();
905     CHECK_NULL_VOID(frontend);
906     auto context = frontend->GetContextValue();
907     auto jsVal = JsConverter::ConvertNapiValueToJsVal(context);
908     info.SetReturnValue(jsVal);
909 }
910 
JSBind(BindingTarget object)911 void JSViewPartialUpdate::JSBind(BindingTarget object)
912 {
913     JSClass<JSViewPartialUpdate>::Declare("NativeViewPartialUpdate");
914     MethodOptions opt = MethodOptions::NONE;
915 
916     JSClass<JSViewPartialUpdate>::StaticMethod("create", &JSViewPartialUpdate::Create, opt);
917     JSClass<JSViewPartialUpdate>::StaticMethod("createRecycle", &JSViewPartialUpdate::CreateRecycle, opt);
918     JSClass<JSViewPartialUpdate>::Method("markNeedUpdate", &JSViewPartialUpdate::MarkNeedUpdate);
919     JSClass<JSViewPartialUpdate>::Method("syncInstanceId", &JSViewPartialUpdate::SyncInstanceId);
920     JSClass<JSViewPartialUpdate>::Method("restoreInstanceId", &JSViewPartialUpdate::RestoreInstanceId);
921     JSClass<JSViewPartialUpdate>::CustomMethod("getInstanceId", &JSViewPartialUpdate::GetInstanceId);
922     JSClass<JSViewPartialUpdate>::Method("markStatic", &JSViewPartialUpdate::MarkStatic);
923     JSClass<JSViewPartialUpdate>::Method("finishUpdateFunc", &JSViewPartialUpdate::JsFinishUpdateFunc);
924     JSClass<JSViewPartialUpdate>::Method("setCardId", &JSViewPartialUpdate::JsSetCardId);
925     JSClass<JSViewPartialUpdate>::CustomMethod("getCardId", &JSViewPartialUpdate::JsGetCardId);
926     JSClass<JSViewPartialUpdate>::Method("elmtIdExists", &JSViewPartialUpdate::JsElementIdExists);
927     JSClass<JSViewPartialUpdate>::CustomMethod("isLazyItemRender", &JSViewPartialUpdate::JSGetProxiedItemRenderState);
928     JSClass<JSViewPartialUpdate>::CustomMethod("isFirstRender", &JSViewPartialUpdate::IsFirstRender);
929     JSClass<JSViewPartialUpdate>::CustomMethod(
930         "findChildByIdForPreview", &JSViewPartialUpdate::FindChildByIdForPreview);
931     JSClass<JSViewPartialUpdate>::CustomMethod(
932         "resetRecycleCustomNode", &JSViewPartialUpdate::JSResetRecycleCustomNode);
933     JSClass<JSViewPartialUpdate>::CustomMethod(
934         "queryNavDestinationInfo", &JSViewPartialUpdate::JSGetNavDestinationInfo);
935     JSClass<JSViewPartialUpdate>::CustomMethod("getUIContext", &JSViewPartialUpdate::JSGetUIContext);
936     JSClass<JSViewPartialUpdate>::InheritAndBind<JSViewAbstract>(object, ConstructorCallback, DestructorCallback);
937 }
938 
ConstructorCallback(const JSCallbackInfo & info)939 void JSViewPartialUpdate::ConstructorCallback(const JSCallbackInfo& info)
940 {
941     JSRef<JSObject> thisObj = info.This();
942 
943     // Get js view name by this.constructor.name
944     JSRef<JSObject> constructor = thisObj->GetProperty("constructor");
945     JSRef<JSVal> jsViewName = constructor->GetProperty("name");
946     auto viewName = jsViewName->ToString();
947     auto* instance = new JSViewPartialUpdate(thisObj);
948 
949     auto context = info.GetExecutionContext();
950     instance->SetContext(context);
951     instance->SetJSViewName(viewName);
952 
953     //  The JS object owns the C++ object:
954     // make sure the C++ is not destroyed when RefPtr thisObj goes out of scope
955     // JSView::DestructorCallback has view->DecRefCount()
956     instance->IncRefCount();
957 
958     info.SetReturnValue(instance);
959 }
960 
DestructorCallback(JSViewPartialUpdate * view)961 void JSViewPartialUpdate::DestructorCallback(JSViewPartialUpdate* view)
962 {
963     if (view == nullptr) {
964         return;
965     }
966     view->DecRefCount();
967 }
968 
969 // ===========================================================
970 // partial update own functions start below
971 // ===========================================================
972 
JsFinishUpdateFunc(int32_t elmtId)973 void JSViewPartialUpdate::JsFinishUpdateFunc(int32_t elmtId)
974 {
975     ViewPartialUpdateModel::GetInstance()->FinishUpdate(
976         viewNode_, elmtId, [weak = AceType::WeakClaim(this)](const UpdateTask& task) {
977             auto jsView = weak.Upgrade();
978             if (jsView) {
979                 jsView->pendingUpdateTasks_.push_back(task);
980             }
981         });
982 }
983 
JsElementIdExists(int32_t elmtId)984 bool JSViewPartialUpdate::JsElementIdExists(int32_t elmtId)
985 {
986     return ElementRegister::GetInstance()->Exists(elmtId);
987 }
988 
JSGetProxiedItemRenderState(const JSCallbackInfo & info)989 void JSViewPartialUpdate::JSGetProxiedItemRenderState(const JSCallbackInfo& info)
990 {
991     if (info.Length() != 1) {
992         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
993         return;
994     }
995     const auto elmtId = info[0]->ToNumber<int32_t>();
996 
997     if (elmtId == ElementRegister::UndefinedElementId) {
998         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
999         return;
1000     }
1001 
1002     // TODO: Check this return value
1003     auto result = false;
1004 
1005     // set boolean return value to JS
1006     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
1007 }
1008 
IsFirstRender(const JSCallbackInfo & info)1009 void JSViewPartialUpdate::IsFirstRender(const JSCallbackInfo& info)
1010 {
1011     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(isFirstRender_)));
1012 }
1013 
FindChildByIdForPreview(const JSCallbackInfo & info)1014 void JSViewPartialUpdate::FindChildByIdForPreview(const JSCallbackInfo& info)
1015 {
1016     if (!info[0]->IsNumber()) {
1017         return;
1018     }
1019     std::string viewId = std::to_string(info[0]->ToNumber<int32_t>());
1020     JSRef<JSObject> targetView = Framework::JSViewStackProcessor::GetViewById(viewId);
1021     info.SetReturnValue(targetView);
1022     return;
1023 }
1024 
1025 } // namespace OHOS::Ace::Framework
1026