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