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