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