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