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