1 /*
2 * Copyright (c) 2022-2025 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 #include "core/components_ng/base/ui_node.h"
16
17 #include "base/log/ace_checker.h"
18 #include "base/log/dump_log.h"
19 #include "base/utils/feature_param.h"
20 #include "bridge/common/utils/engine_helper.h"
21 #include "core/common/builder_util.h"
22 #include "core/common/multi_thread_build_manager.h"
23 #include "core/components_ng/base/ui_node_gc.h"
24 #include "core/components_ng/pattern/text/text_layout_property.h"
25 #include "core/components_ng/token_theme/token_theme_storage.h"
26 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
27 #include "frameworks/core/pipeline/base/element_register_multi_thread.h"
28
29 namespace OHOS::Ace::NG {
30
31 std::atomic<int64_t> currentAccessibilityId_ = 0;
32 const std::set<std::string> UINode::layoutTags_ = { "Flex", "Stack", "Row", "Column", "WindowScene", "root",
33 "__Common__", "Swiper", "Grid", "GridItem", "page", "stage", "FormComponent", "Tabs", "TabContent" };
34
UINode(const std::string & tag,int32_t nodeId,bool isRoot)35 UINode::UINode(const std::string& tag, int32_t nodeId, bool isRoot)
36 : tag_(tag), nodeId_(nodeId), accessibilityId_(currentAccessibilityId_++), isRoot_(isRoot)
37 {
38 if (MultiThreadBuildManager::IsThreadSafeNodeScope()) {
39 isThreadSafeNode_ = true;
40 isFree_ = true;
41 }
42 if (AceChecker::IsPerformanceCheckEnabled()) {
43 auto pos = EngineHelper::GetPositionOnJsCode();
44 nodeInfo_ = std::make_unique<PerformanceCheckNode>();
45 nodeInfo_->codeRow = std::get<1>(pos);
46 nodeInfo_->codeCol = std::get<2>(pos);
47 nodeInfo_->pagePath = std::get<0>(pos);
48 }
49 apiVersion_ = Container::GetCurrentApiTargetVersion();
50 #ifdef UICAST_COMPONENT_SUPPORTED
51 do {
52 auto container = Container::Current();
53 CHECK_NULL_BREAK(container);
54 auto distributedUI = container->GetDistributedUI();
55 CHECK_NULL_BREAK(distributedUI);
56 distributedUI->AddNewNode(nodeId_);
57 } while (false);
58 #endif
59 instanceId_ = Container::CurrentId();
60 nodeStatus_ = ViewStackProcessor::GetInstance()->IsBuilderNode() ? NodeStatus::BUILDER_NODE_OFF_MAINTREE
61 : NodeStatus::NORMAL_NODE;
62 if (SystemProperties::ConfigChangePerform()) {
63 auto currentContainer = Container::GetContainer(instanceId_);
64 isDarkMode_ = currentContainer ? (currentContainer->GetColorMode() == ColorMode::DARK) : false;
65 }
66 uiNodeGcEnable_ = FeatureParam::IsUINodeGcEnabled();
67 }
68
~UINode()69 UINode::~UINode()
70 {
71 #ifdef UICAST_COMPONENT_SUPPORTED
72 do {
73 auto container = Container::Current();
74 CHECK_NULL_BREAK(container);
75 auto distributedUI = container->GetDistributedUI();
76 CHECK_NULL_BREAK(distributedUI);
77 if (hostPageId_ == distributedUI->GetCurrentPageId()) {
78 distributedUI->AddDeletedNode(nodeId_);
79 }
80 } while (false);
81 #endif
82
83 if (!removeSilently_) {
84 ElementRegister::GetInstance()->RemoveItem(nodeId_);
85 } else {
86 ElementRegister::GetInstance()->RemoveItemSilently(nodeId_);
87 }
88 if (isThreadSafeNode_) {
89 ElementRegisterMultiThread::GetInstance()->RemoveThreadSafeNode(nodeId_);
90 }
91 if (propInspectorId_.has_value()) {
92 ElementRegister::GetInstance()->RemoveFrameNodeByInspectorId(propInspectorId_.value_or(""), nodeId_);
93 }
94 if (!onMainTree_) {
95 return;
96 }
97 if (context_) {
98 context_->RemoveAttachedNode(this);
99 }
100 onMainTree_ = false;
101 if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
102 nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
103 }
104 }
105
MaybeRelease()106 bool UINode::MaybeRelease()
107 {
108 if (!isThreadSafeNode_ || MultiThreadBuildManager::IsOnUIThread()) {
109 if (uiNodeGcEnable_) {
110 UiNodeGc::OnReleaseFunc(this);
111 return false;
112 }
113 return true;
114 }
115 auto pipeline = GetContext();
116 CHECK_NULL_RETURN(pipeline, true);
117 auto executor = pipeline->GetTaskExecutor();
118 CHECK_NULL_RETURN(executor, true);
119 return !executor->PostTask([this] { delete this; }, TaskExecutor::TaskType::UI, "ArkUIDestroyUINode");
120 }
121
RegisterReleaseFunc(bool enableRegister)122 void UINode::RegisterReleaseFunc(bool enableRegister)
123 {
124 uiNodeGcEnable_ = enableRegister;
125 }
126
OnDelete()127 void UINode::OnDelete()
128 {
129 disappearingChildren_.clear();
130 children_.clear();
131 }
132
AttachContext(PipelineContext * context,bool recursive)133 void UINode::AttachContext(PipelineContext* context, bool recursive)
134 {
135 CHECK_NULL_VOID(context);
136 context_ = context;
137 context_->RegisterAttachedNode(this);
138 instanceId_ = context->GetInstanceId();
139 if (updateJSInstanceCallback_) {
140 updateJSInstanceCallback_(instanceId_);
141 }
142 if (recursive) {
143 for (auto& child : children_) {
144 child->AttachContext(context, recursive);
145 }
146 }
147 }
148
DetachContext(bool recursive)149 void UINode::DetachContext(bool recursive)
150 {
151 CHECK_NULL_VOID(context_);
152 context_->DetachNode(Claim(this));
153 context_ = nullptr;
154 instanceId_ = INSTANCE_ID_UNDEFINED;
155 if (recursive) {
156 for (auto& child : children_) {
157 child->DetachContext(recursive);
158 }
159 }
160 }
161
AddChild(const RefPtr<UINode> & child,int32_t slot,bool silently,bool addDefaultTransition,bool addModalUiextension)162 void UINode::AddChild(const RefPtr<UINode>& child, int32_t slot,
163 bool silently, bool addDefaultTransition, bool addModalUiextension)
164 {
165 CHECK_NULL_VOID(child);
166 if (child->GetAncestor() == this) {
167 auto it = std::find(children_.begin(), children_.end(), child);
168 if (it != children_.end()) {
169 return;
170 }
171 }
172
173 // remove from disappearing children
174 RemoveDisappearingChild(child);
175 auto it = children_.begin();
176 std::advance(it, slot);
177 if (!addModalUiextension && modalUiextensionCount_ > 0) {
178 bool canAddChild = CanAddChildWhenTopNodeIsModalUec(it);
179 if (!canAddChild) {
180 LOGW("Current Node(id: %{public}d) is prohibited add child(tag %{public}s, id: %{public}d), "
181 "Current modalUiextension count is : %{public}d",
182 nodeId_, child->GetTag().c_str(), child->GetId(), modalUiextensionCount_);
183 return;
184 } else {
185 LOGI("Child(tag %{public}s, id: %{public}d) must under modalUec, which count is: %{public}d",
186 child->GetTag().c_str(), child->GetId(), modalUiextensionCount_);
187 }
188 }
189 DoAddChild(it, child, silently, addDefaultTransition);
190 }
191
CanAddChildWhenTopNodeIsModalUec(std::list<RefPtr<UINode>>::iterator & curIter)192 bool UINode::CanAddChildWhenTopNodeIsModalUec(std::list<RefPtr<UINode>>::iterator& curIter)
193 {
194 if (children_.empty()) {
195 return true;
196 }
197
198 auto preIter = curIter;
199 preIter--;
200 // Gernerally, uiContent instance is allowwd to have multiple modalUecs.
201 // Therefore, need to check all modalUec's isAllowAddChildBelowModalUec.
202 while (preIter != children_.begin()) {
203 if (preIter == children_.end()) {
204 break;
205 }
206
207 if ((*preIter)->GetTag() != V2::MODAL_PAGE_TAG) {
208 break;
209 }
210
211 if (!(*preIter)->IsAllowAddChildBelowModalUec()) {
212 return false;
213 }
214
215 curIter--;
216 preIter--;
217 }
218
219 return true;
220 }
221
AddChildAfter(const RefPtr<UINode> & child,const RefPtr<UINode> & siblingNode)222 void UINode::AddChildAfter(const RefPtr<UINode>& child, const RefPtr<UINode>& siblingNode)
223 {
224 CHECK_NULL_VOID(child);
225 CHECK_NULL_VOID(siblingNode);
226 if (child->GetAncestor() == this) {
227 auto it = std::find(children_.begin(), children_.end(), child);
228 if (it != children_.end()) {
229 LOGW("Child node already exists. Existing child nodeId %{public}d, add %{public}s child nodeId nodeId "
230 "%{public}d",
231 (*it)->GetId(), child->GetTag().c_str(), child->GetId());
232 return;
233 }
234 }
235
236 // remove from disappearing children
237 RemoveDisappearingChild(child);
238 auto siblingNodeIter = std::find(children_.begin(), children_.end(), siblingNode);
239 if (siblingNodeIter != children_.end()) {
240 DoAddChild(++siblingNodeIter, child, false);
241 return;
242 }
243 auto it = children_.begin();
244 std::advance(it, -1);
245 DoAddChild(it, child, false);
246 }
247
AddChildBefore(const RefPtr<UINode> & child,const RefPtr<UINode> & siblingNode)248 void UINode::AddChildBefore(const RefPtr<UINode>& child, const RefPtr<UINode>& siblingNode)
249 {
250 CHECK_NULL_VOID(child);
251 CHECK_NULL_VOID(siblingNode);
252 if (child->GetAncestor() == this) {
253 auto it = std::find(children_.begin(), children_.end(), child);
254 if (it != children_.end()) {
255 LOGW("Child node already exists. Existing child nodeId %{public}d, add %{public}s child nodeId nodeId "
256 "%{public}d",
257 (*it)->GetId(), child->GetTag().c_str(), child->GetId());
258 return;
259 }
260 }
261 // remove from disappearing children
262 RemoveDisappearingChild(child);
263 auto siblingNodeIter = std::find(children_.begin(), children_.end(), siblingNode);
264 if (siblingNodeIter != children_.end()) {
265 DoAddChild(siblingNodeIter, child, false);
266 return;
267 }
268 auto it = children_.begin();
269 std::advance(it, -1);
270 DoAddChild(it, child, false);
271 }
272
TraversingCheck(RefPtr<UINode> node,bool withAbort)273 void UINode::TraversingCheck(RefPtr<UINode> node, bool withAbort)
274 {
275 if (!isTraversing_) {
276 return;
277 }
278
279 if (withAbort) {
280 if (node) {
281 LOGF_ABORT("Try to remove the child([%{public}s][%{public}d]) of "
282 "node [%{public}s][%{public}d] when its children is traversing",
283 node->GetTag().c_str(), node->GetId(), tag_.c_str(), nodeId_);
284 } else {
285 LOGF_ABORT("Try to remove all the children of "
286 "node [%{public}s][%{public}d] when its children is traversing",
287 tag_.c_str(), nodeId_);
288 }
289 }
290
291 if (node) {
292 LOGE("Try to remove the child([%{public}s][%{public}d]) of "
293 "node [%{public}s][%{public}d] when its children is traversing",
294 node->GetTag().c_str(), node->GetId(), tag_.c_str(), nodeId_);
295 } else {
296 LOGE("Try to remove all the children of "
297 "node [%{public}s][%{public}d] when its children is traversing",
298 tag_.c_str(), nodeId_);
299 }
300 LogBacktrace();
301 }
302
RemoveChild(const RefPtr<UINode> & child,bool allowTransition)303 std::list<RefPtr<UINode>>::iterator UINode::RemoveChild(const RefPtr<UINode>& child, bool allowTransition)
304 {
305 CHECK_NULL_RETURN(child, children_.end());
306
307 auto iter = std::find(children_.begin(), children_.end(), child);
308 if (iter == children_.end()) {
309 return children_.end();
310 }
311
312 // the node set isInDestroying state when destroying in pop animation
313 // when in isInDestroying state node should not DetachFromMainTree preventing pop page from being white
314 if (IsDestroyingState() && context_ && !context_->IsDestroyed()) {
315 return children_.end();
316 }
317 // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to the
318 // disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved until the
319 // transition has finished. We can then perform the necessary cleanup after the transition is complete.
320 if ((*iter)->OnRemoveFromParent(allowTransition)) {
321 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
322 RemoveDisappearingChild(child);
323 } else {
324 // else move child into disappearing children, skip syncing render tree
325 AddDisappearingChild(child, std::distance(children_.begin(), iter));
326 }
327 MarkNeedSyncRenderTree(true);
328 // Iter maybe lost in OnRemoveFromParent, needs reacquire.
329 iter = std::find(children_.begin(), children_.end(), child);
330 if (iter == children_.end()) {
331 LOGW("Iter is qeual to children end");
332 return children_.end();
333 }
334 TraversingCheck(*iter);
335 (*iter)->SetAncestor(nullptr);
336 auto result = children_.erase(iter);
337 return result;
338 }
339
RemoveChildSilently(const RefPtr<UINode> & child)340 bool UINode::RemoveChildSilently(const RefPtr<UINode>& child)
341 {
342 CHECK_NULL_RETURN(child, false);
343 auto iter = std::find(children_.begin(), children_.end(), child);
344 if (IsDestroyingState() || iter == children_.end()) {
345 return false;
346 }
347 children_.erase(iter);
348 return true;
349 }
350
RemoveChildAndReturnIndex(const RefPtr<UINode> & child)351 int32_t UINode::RemoveChildAndReturnIndex(const RefPtr<UINode>& child)
352 {
353 auto result = RemoveChild(child);
354 return std::distance(children_.begin(), result);
355 }
356
RemoveChildAtIndex(int32_t index)357 void UINode::RemoveChildAtIndex(int32_t index)
358 {
359 auto children = GetChildren();
360 if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
361 return;
362 }
363 auto iter = children.begin();
364 std::advance(iter, index);
365 RemoveChild(*iter);
366 }
367
GetChildAtIndex(int32_t index) const368 RefPtr<UINode> UINode::GetChildAtIndex(int32_t index) const
369 {
370 auto& children = GetChildren();
371 if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
372 return nullptr;
373 }
374 auto iter = children.begin();
375 std::advance(iter, index);
376 if (iter != children.end()) {
377 return *iter;
378 }
379 return nullptr;
380 }
381
GetChildIndex(const RefPtr<UINode> & child) const382 int32_t UINode::GetChildIndex(const RefPtr<UINode>& child) const
383 {
384 int32_t index = 0;
385 for (const auto& iter : GetChildren()) {
386 if (iter == child) {
387 return index;
388 }
389 index++;
390 }
391 return -1;
392 }
393
ReplaceChild(const RefPtr<UINode> & oldNode,const RefPtr<UINode> & newNode)394 void UINode::ReplaceChild(const RefPtr<UINode>& oldNode, const RefPtr<UINode>& newNode)
395 {
396 if (!oldNode) {
397 if (newNode) {
398 AddChild(newNode);
399 }
400 return;
401 }
402
403 auto iter = RemoveChild(oldNode);
404 DoAddChild(iter, newNode, false, false);
405 }
406
Clean(bool cleanDirectly,bool allowTransition,int32_t branchId)407 void UINode::Clean(bool cleanDirectly, bool allowTransition, int32_t branchId)
408 {
409 bool needSyncRenderTree = false;
410 bool isNotV2IfNode = (tag_ != V2::JS_IF_ELSE_ETS_TAG);
411 int32_t index = 0;
412
413 auto children = GetChildren();
414 for (const auto& child : children) {
415 // traverse down the child subtree to mark removing and find needs to hold subtree, if found add it to pending
416 if (!cleanDirectly && child->MarkRemoving()) {
417 ElementRegister::GetInstance()->AddPendingRemoveNode(child);
418 }
419 // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to
420 // the disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved
421 // until the transition has finished. We can then perform the necessary cleanup after the transition is
422 // complete.
423 if (child->OnRemoveFromParent(allowTransition)) {
424 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
425 RemoveDisappearingChild(child);
426 needSyncRenderTree = true;
427 } else {
428 // else move child into disappearing children, skip syncing render tree
429 AddDisappearingChild(child, index, branchId);
430 }
431 if (isNotV2IfNode) {
432 child->SetAncestor(nullptr);
433 }
434 ++index;
435 }
436
437 if (isNotV2IfNode) {
438 children_.clear();
439 }
440 MarkNeedSyncRenderTree(true);
441 }
442
MountToParent(const RefPtr<UINode> & parent,int32_t slot,bool silently,bool addDefaultTransition,bool addModalUiextension)443 void UINode::MountToParent(const RefPtr<UINode>& parent,
444 int32_t slot, bool silently, bool addDefaultTransition, bool addModalUiextension)
445 {
446 CHECK_NULL_VOID(parent);
447 parent->AddChild(AceType::Claim(this), slot, silently, addDefaultTransition, addModalUiextension);
448 if (parent->IsInDestroying()) {
449 parent->SetChildrenInDestroying();
450 }
451 if (parent->GetPageId() != 0) {
452 SetHostPageId(parent->GetPageId());
453 }
454 AfterMountToParent();
455 }
456
MountToParentAfter(const RefPtr<UINode> & parent,const RefPtr<UINode> & siblingNode)457 void UINode::MountToParentAfter(const RefPtr<UINode>& parent, const RefPtr<UINode>& siblingNode)
458 {
459 CHECK_NULL_VOID(parent);
460 parent->AddChildAfter(AceType::Claim(this), siblingNode);
461 if (parent->IsInDestroying()) {
462 parent->SetChildrenInDestroying();
463 }
464 if (parent->GetPageId() != 0) {
465 SetHostPageId(parent->GetPageId());
466 }
467 AfterMountToParent();
468 }
469
MountToParentBefore(const RefPtr<UINode> & parent,const RefPtr<UINode> & siblingNode)470 void UINode::MountToParentBefore(const RefPtr<UINode>& parent, const RefPtr<UINode>& siblingNode)
471 {
472 CHECK_NULL_VOID(parent);
473 parent->AddChildBefore(AceType::Claim(this), siblingNode);
474 if (parent->IsInDestroying()) {
475 parent->SetChildrenInDestroying();
476 }
477 if (parent->GetPageId() != 0) {
478 SetHostPageId(parent->GetPageId());
479 }
480 AfterMountToParent();
481 }
482
UpdateConfigurationUpdate()483 void UINode::UpdateConfigurationUpdate()
484 {
485 if (onMainTree_) {
486 return;
487 }
488 auto pipeline = NG::PipelineContext::GetCurrentContext();
489 CHECK_NULL_VOID(pipeline);
490 UpdateConfigurationUpdate(pipeline->GetConfigurationChange());
491 }
492
UpdateConfigurationUpdate(const ConfigurationChange & configurationChange)493 void UINode::UpdateConfigurationUpdate(const ConfigurationChange& configurationChange)
494 {
495 OnConfigurationUpdate(configurationChange);
496 if (needCallChildrenUpdate_) {
497 auto children = GetChildren();
498 for (const auto& child : children) {
499 if (!child) {
500 continue;
501 }
502 child->UpdateConfigurationUpdate(configurationChange);
503 }
504 }
505 }
506
OnRemoveFromParent(bool allowTransition)507 bool UINode::OnRemoveFromParent(bool allowTransition)
508 {
509 if (IsDestroyingState() && context_ && !context_->IsDestroyed()) {
510 return false;
511 }
512 // The recursive flag will used by RenderContext, if recursive flag is false,
513 // it may trigger transition
514 DetachFromMainTree(!allowTransition);
515 if (allowTransition && !RemoveImmediately()) {
516 return false;
517 }
518 ResetParent();
519 return true;
520 }
521
ResetParent()522 void UINode::ResetParent()
523 {
524 ancestor_.Reset();
525 parent_.Reset();
526 depth_ = -1;
527 UpdateThemeScopeId(0);
528 }
529
530 namespace {
operator <<(std::ostream & ss,const RefPtr<UINode> & node)531 std::ostream& operator<<(std::ostream& ss, const RefPtr<UINode>& node)
532 {
533 return ss << node->GetId() << "(" << node->GetTag() << "," << node->GetDepth()
534 << "," << node->GetChildren().size() << ")";
535 }
536
ToString(const RefPtr<UINode> & node)537 std::string ToString(const RefPtr<UINode>& node)
538 {
539 std::stringstream ss;
540 ss << node;
541 for (auto parent = node->GetParent(); parent; parent = parent->GetParent()) {
542 ss << "->" << parent;
543 }
544 return ss.str();
545 }
546
LoopDetected(const RefPtr<UINode> & child,const RefPtr<UINode> & current)547 void LoopDetected(const RefPtr<UINode>& child, const RefPtr<UINode>& current)
548 {
549 auto childNode = ToString(child);
550 auto currentNode = ToString(current);
551
552 constexpr size_t totalLengthLimit = 900; // hilog oneline length limit is 1024
553 constexpr size_t childLengthLimit = 100;
554 static_assert(totalLengthLimit > childLengthLimit, "totalLengthLimit too small");
555 constexpr size_t currentLengthLimit = totalLengthLimit - childLengthLimit;
556
557 // log full childNode info in case of hilog length limit reached
558 if (childNode.length() > childLengthLimit) {
559 auto s = childNode.c_str();
560 for (size_t i = 0; i < childNode.length(); i += totalLengthLimit) {
561 LOGI("child.%{public}zu:[%{public}.*s]", i, (int)totalLengthLimit, s + i);
562 }
563 }
564
565 // log full currentNode info in case of hilog length limit reached
566 if (currentNode.length() > currentLengthLimit) {
567 auto s = currentNode.c_str();
568 for (size_t i = 0; i < currentNode.length(); i += totalLengthLimit) {
569 LOGI("current.%{public}zu:[%{public}.*s]", i, (int)totalLengthLimit, s + i);
570 }
571 }
572
573 if (SystemProperties::GetLayoutDetectEnabled()) {
574 LOGF_ABORT("LoopDetected: child[%{public}.*s] vs current[%{public}.*s]",
575 (int)childLengthLimit, childNode.c_str(), (int)currentLengthLimit, currentNode.c_str());
576 } else {
577 LOGE("LoopDetected: child[%{public}.*s] vs current[%{public}.*s]",
578 (int)childLengthLimit, childNode.c_str(), (int)currentLengthLimit, currentNode.c_str());
579 LogBacktrace();
580 }
581 }
582
DetectLoop(const RefPtr<UINode> & child,const RefPtr<UINode> & current)583 bool DetectLoop(const RefPtr<UINode>& child, const RefPtr<UINode>& current)
584 {
585 if ((child->GetDepth() > 0 && child->GetDepth() < INT32_MAX) || child == current) {
586 for (auto parent = current; parent; parent = parent->GetParent()) {
587 if (parent == child) {
588 LoopDetected(child, current);
589 return true;
590 }
591 }
592 }
593 return false;
594 }
595 }
596
DoAddChild(std::list<RefPtr<UINode>>::iterator & it,const RefPtr<UINode> & child,bool silently,bool addDefaultTransition)597 void UINode::DoAddChild(
598 std::list<RefPtr<UINode>>::iterator& it, const RefPtr<UINode>& child, bool silently, bool addDefaultTransition)
599 {
600 if (DetectLoop(child, Claim(this))) {
601 return;
602 }
603 children_.insert(it, child);
604
605 if (IsAccessibilityVirtualNode()) {
606 auto parentVirtualNode = GetVirtualNodeParent().Upgrade();
607 if (parentVirtualNode) {
608 child->SetAccessibilityNodeVirtual();
609 child->SetAccessibilityVirtualNodeParent(parentVirtualNode);
610 }
611 }
612
613 UpdateDrawChildObserver(child);
614
615 child->SetParent(WeakClaim(this), false);
616 auto themeScopeId = GetThemeScopeId();
617 if (child->IsAllowUseParentTheme() && child->GetThemeScopeId() != themeScopeId) {
618 child->UpdateThemeScopeId(themeScopeId);
619 }
620 child->SetDepth(depth_ + 1);
621 if (nodeStatus_ != NodeStatus::NORMAL_NODE) {
622 child->UpdateNodeStatus(nodeStatus_);
623 }
624
625 if (!silently && onMainTree_) {
626 child->AttachToMainTree(!addDefaultTransition, context_);
627 }
628 MarkNeedSyncRenderTree(true);
629 ProcessIsInDestroyingForReuseableNode(child);
630 // Forced update colormode when builderNode attach to main tree.
631 if (SystemProperties::ConfigChangePerform() && child->nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE &&
632 context_) {
633 auto colorMode = static_cast<int32_t>(context_->GetColorMode());
634 if (child->CheckIsDarkMode() != colorMode) {
635 context_->SetIsSystemColorChange(true);
636 SetRerenderable(true);
637 SetMeasureAnyway(true);
638 SetShouldClearCache(true);
639 NotifyColorModeChange(colorMode);
640 }
641 }
642 }
643
GetBestBreakPoint(RefPtr<UINode> & breakPointChild,RefPtr<UINode> & breakPointParent)644 void UINode::GetBestBreakPoint(RefPtr<UINode>& breakPointChild, RefPtr<UINode>& breakPointParent)
645 {
646 while (breakPointParent && !breakPointChild->IsDisappearing()) {
647 // recursively looking up the node tree, until we reach the breaking point (IsDisappearing() == true).
648 // Because when trigger transition, only the breakPoint will be marked as disappearing and
649 // moved to disappearingChildren.
650 breakPointChild = breakPointParent;
651 breakPointParent = breakPointParent->GetParent();
652 }
653 RefPtr<UINode> betterChild = breakPointChild;
654 RefPtr<UINode> betterParent = breakPointParent;
655 // when current breakPointParent is UINode, looking up the node tree to see whether there is a better breakPoint.
656 while (betterParent && !InstanceOf<FrameNode>(betterParent)) {
657 if (betterChild->IsDisappearing()) {
658 if (!betterChild->RemoveImmediately()) {
659 break;
660 }
661 breakPointChild = betterChild;
662 breakPointParent = betterParent;
663 }
664 betterChild = betterParent;
665 betterParent = betterParent->GetParent();
666 }
667 }
668
RemoveFromParentCleanly(const RefPtr<UINode> & child,const RefPtr<UINode> & parent)669 void UINode::RemoveFromParentCleanly(const RefPtr<UINode>& child, const RefPtr<UINode>& parent)
670 {
671 if (!parent->RemoveDisappearingChild(child)) {
672 auto& children = parent->ModifyChildren();
673 auto iter = std::find(children.begin(), children.end(), child);
674 if (iter != children.end()) {
675 parent->TraversingCheck(*iter);
676 (*iter)->SetAncestor(nullptr);
677 children.erase(iter);
678 }
679 }
680 auto frameChild = DynamicCast<FrameNode>(child);
681 if (frameChild->GetRenderContext()->HasTransitionOutAnimation()) {
682 // delete the real breakPoint.
683 RefPtr<UINode> breakPointChild = child;
684 RefPtr<UINode> breakPointParent = parent;
685 GetBestBreakPoint(breakPointChild, breakPointParent);
686 if (breakPointParent && breakPointChild->RemoveImmediately()) {
687 // Result of RemoveImmediately of the breakPointChild is true and
688 // result of RemoveImmediately of the child is false,
689 // so breakPointChild must be different from child in this branch.
690 breakPointParent->RemoveDisappearingChild(breakPointChild);
691 breakPointParent->MarkNeedSyncRenderTree();
692 }
693 }
694 }
695
GetParentFrameNode() const696 RefPtr<FrameNode> UINode::GetParentFrameNode() const
697 {
698 auto parent = GetParent();
699 while (parent) {
700 auto parentFrame = AceType::DynamicCast<FrameNode>(parent);
701 if (parentFrame) {
702 return parentFrame;
703 }
704 parent = parent->GetParent();
705 }
706 return nullptr;
707 }
708
GetParentCustomNode() const709 RefPtr<CustomNode> UINode::GetParentCustomNode() const
710 {
711 auto parent = GetParent();
712 while (parent) {
713 auto customNode = AceType::DynamicCast<CustomNode>(parent);
714 if (customNode) {
715 return customNode;
716 }
717 parent = parent->GetParent();
718 }
719 return nullptr;
720 }
721
GetFocusParent() const722 RefPtr<FrameNode> UINode::GetFocusParent() const
723 {
724 auto parentUi = GetParent();
725 while (parentUi) {
726 auto parentFrame = AceType::DynamicCast<FrameNode>(parentUi);
727 if (!parentFrame) {
728 parentUi = parentUi->GetParent();
729 continue;
730 }
731 auto type = parentFrame->GetFocusType();
732 if (type == FocusType::SCOPE) {
733 return parentFrame;
734 }
735 if (type == FocusType::NODE) {
736 return nullptr;
737 }
738 parentUi = parentUi->GetParent();
739 }
740 return nullptr;
741 }
742
GetFocusParentWithBoundary() const743 RefPtr<FrameNode> UINode::GetFocusParentWithBoundary() const
744 {
745 auto parentUi = GetParent();
746 while (parentUi) {
747 if (parentUi->GetTag() == V2::SCREEN_ETS_TAG) {
748 return nullptr;
749 }
750 auto parentFrame = AceType::DynamicCast<FrameNode>(parentUi);
751 if (!parentFrame) {
752 parentUi = parentUi->GetParent();
753 continue;
754 }
755 auto type = parentFrame->GetFocusType();
756 if (type == FocusType::SCOPE) {
757 return parentFrame;
758 }
759 if (type == FocusType::NODE) {
760 return nullptr;
761 }
762 parentUi = parentUi->GetParent();
763 }
764 return nullptr;
765 }
766
GetFirstFocusHubChild() const767 RefPtr<FocusHub> UINode::GetFirstFocusHubChild() const
768 {
769 const auto* frameNode = AceType::DynamicCast<FrameNode>(this);
770 if (frameNode) {
771 auto focusHub = frameNode->GetFocusHub();
772 if (focusHub && focusHub->GetFocusType() != FocusType::DISABLE) {
773 return focusHub;
774 }
775 }
776 for (const auto& child : GetChildren()) {
777 auto focusHub = child->GetFirstFocusHubChild();
778 if (focusHub) {
779 return focusHub;
780 }
781 }
782 return nullptr;
783 }
784
GetFocusChildren(std::list<RefPtr<FrameNode>> & children) const785 void UINode::GetFocusChildren(std::list<RefPtr<FrameNode>>& children) const
786 {
787 auto uiChildren = GetChildren();
788 for (const auto& uiChild : uiChildren) {
789 auto frameChild = AceType::DynamicCast<FrameNode>(uiChild);
790 if (frameChild && frameChild->GetFocusType() != FocusType::DISABLE) {
791 children.emplace_back(frameChild);
792 } else {
793 uiChild->GetFocusChildren(children);
794 }
795 }
796 }
797
GetCurrentChildrenFocusHub(std::list<RefPtr<FocusHub>> & focusNodes)798 void UINode::GetCurrentChildrenFocusHub(std::list<RefPtr<FocusHub>>& focusNodes)
799 {
800 for (const auto& uiChild : children_) {
801 auto frameChild = AceType::DynamicCast<FrameNode>(Referenced::RawPtr(uiChild));
802 if (frameChild && frameChild->GetFocusType() != FocusType::DISABLE) {
803 const auto focusHub = frameChild->GetFocusHub();
804 if (focusHub) {
805 focusNodes.emplace_back(focusHub);
806 }
807 } else {
808 uiChild->GetCurrentChildrenFocusHub(focusNodes);
809 }
810 }
811 }
812
AttachToMainTree(bool recursive,PipelineContext * context)813 void UINode::AttachToMainTree(bool recursive, PipelineContext* context)
814 {
815 if (onMainTree_) {
816 return;
817 }
818 if (context) {
819 context->SetIsTransFlag(true);
820 }
821 // the context should not be nullptr.
822 AttachContext(context, false);
823 onMainTree_ = true;
824 if (nodeStatus_ == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
825 nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE;
826 }
827 isRemoving_ = false;
828 if (isThreadSafeNode_) {
829 isFree_ = false;
830 ElementRegister::GetInstance()->AddUINode(Claim(this));
831 ExecuteAfterAttachMainTreeTasks();
832 }
833 OnAttachToMainTree(recursive);
834 // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
835 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
836 for (const auto& child : GetChildren()) {
837 child->AttachToMainTree(isRecursive, context);
838 }
839 if (context && context->IsOpenInvisibleFreeze()) {
840 auto parent = GetParent();
841 // if it does not has parent, reset the flag.
842 SetFreeze(parent ? parent->isFreeze_ : false);
843 }
844 }
845
AttachToMainTree(bool recursive)846 [[deprecated]] void UINode::AttachToMainTree(bool recursive)
847 {
848 if (onMainTree_) {
849 return;
850 }
851 onMainTree_ = true;
852 if (nodeStatus_ == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
853 nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE;
854 }
855 isRemoving_ = false;
856 OnAttachToMainTree(recursive);
857 // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
858 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
859 for (const auto& child : GetChildren()) {
860 child->AttachToMainTree(isRecursive);
861 }
862 }
863
CheckThreadSafeNodeTree(bool needCheck)864 bool UINode::CheckThreadSafeNodeTree(bool needCheck)
865 {
866 bool needCheckChild = needCheck;
867 if (needCheck && !isThreadSafeNode_) {
868 // Remind developers that it is unsafe to operate node trees containing unsafe nodes on non UI threads.
869 TAG_LOGW(AceLogTag::ACE_NATIVE_NODE,
870 "CheckIsThreadSafeNodeTree failed. thread safe node tree contains unsafe node: %{public}d", GetId());
871 needCheckChild = false;
872 } else if (isThreadSafeNode_) {
873 needCheckChild = true;
874 }
875 return needCheckChild;
876 }
877
DetachFromMainTree(bool recursive,bool needCheckThreadSafeNodeTree)878 void UINode::DetachFromMainTree(bool recursive, bool needCheckThreadSafeNodeTree)
879 {
880 if (!onMainTree_) {
881 return;
882 }
883 if (IsDestroyingState() && context_ && !context_->IsDestroyed()) {
884 return;
885 }
886 onMainTree_ = false;
887 if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
888 nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
889 }
890 isRemoving_ = true;
891 auto context = context_;
892 DetachContext(false);
893 if (isNodeAdapter_) {
894 std::list<RefPtr<UINode>> nodes;
895 RefPtr<UINode> uiNode = AceType::Claim<UINode>(this);
896 BuilderUtils::GetBuilderNodes(uiNode, nodes);
897 BuilderUtils::RemoveBuilderFromParent(GetParent(), nodes);
898 }
899 OnDetachFromMainTree(recursive, context);
900 // if recursive = false, recursively call DetachFromMainTree(false), until we reach the first FrameNode.
901 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
902 isTraversing_ = true;
903 std::list<RefPtr<UINode>> children = GetChildren();
904 bool needCheckChild = CheckThreadSafeNodeTree(needCheckThreadSafeNodeTree);
905 for (const auto& child : children) {
906 child->DetachFromMainTree(isRecursive, needCheckChild);
907 }
908 if (isThreadSafeNode_) {
909 ElementRegister::GetInstance()->RemoveItemSilently(GetId());
910 isFree_ = true;
911 }
912 isTraversing_ = false;
913 }
914
SetUserFreeze(bool isUserFreeze)915 void UINode::SetUserFreeze(bool isUserFreeze)
916 {
917 userFreeze_ = isUserFreeze;
918 }
919
IsUserFreeze()920 bool UINode::IsUserFreeze()
921 {
922 return userFreeze_.has_value() && userFreeze_.value();
923 }
924
SetFreeze(bool isFreeze,bool isForceUpdateFreezeVaule,bool isUserFreeze)925 void UINode::SetFreeze(bool isFreeze, bool isForceUpdateFreezeVaule, bool isUserFreeze)
926 {
927 auto context = GetContext();
928 CHECK_NULL_VOID(context);
929 if (isUserFreeze) {
930 SetUserFreeze(isUserFreeze);
931 } else if (IsUserFreeze()) {
932 return;
933 }
934
935 auto isNeedUpdateFreezeVaule = context->IsOpenInvisibleFreeze() || isForceUpdateFreezeVaule;
936 if (isNeedUpdateFreezeVaule && isFreeze_ != isFreeze) {
937 isFreeze_ = isFreeze;
938 OnFreezeStateChange();
939 UpdateChildrenFreezeState(isFreeze_, isForceUpdateFreezeVaule);
940 }
941 }
942
UpdateChildrenFreezeState(bool isFreeze,bool isForceUpdateFreezeVaule)943 void UINode::UpdateChildrenFreezeState(bool isFreeze, bool isForceUpdateFreezeVaule)
944 {
945 const auto& children = GetChildren(true);
946 for (const auto& child : children) {
947 if (child) {
948 child->SetFreeze(isFreeze, isForceUpdateFreezeVaule);
949 }
950 }
951 }
952
FireCustomDisappear()953 void UINode::FireCustomDisappear()
954 {
955 std::list<RefPtr<UINode>> children = GetChildren();
956 for (const auto& child : children) {
957 child->FireCustomDisappear();
958 }
959 }
960
ProcessOffscreenTask(bool recursive)961 void UINode::ProcessOffscreenTask(bool recursive)
962 {
963 if (useOffscreenProcess_) {
964 return;
965 }
966 useOffscreenProcess_ = true;
967 OnOffscreenProcess(recursive);
968 // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
969 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
970 for (const auto& child : GetChildren()) {
971 child->ProcessOffscreenTask(isRecursive);
972 }
973 }
974
MovePosition(int32_t slot)975 void UINode::MovePosition(int32_t slot)
976 {
977 auto parentNode = parent_.Upgrade();
978 CHECK_NULL_VOID(parentNode);
979
980 auto self = AceType::Claim(this);
981 auto& children = parentNode->children_;
982 auto it = children.end();
983 if (slot >= 0 && static_cast<size_t>(slot) < children.size()) {
984 it = children.begin();
985 std::advance(it, slot);
986 if ((it != children.end()) && (*it == this)) {
987 // Already at the right place
988 return;
989 }
990
991 auto itSelf = std::find(it, children.end(), self);
992 if (itSelf != children.end()) {
993 parentNode->TraversingCheck(*itSelf);
994 children.erase(itSelf);
995 } else {
996 parentNode->TraversingCheck(self);
997 children.remove(self);
998 ++it;
999 }
1000 } else {
1001 parentNode->TraversingCheck(self);
1002 children.remove(self);
1003 }
1004 children.insert(it, self);
1005 parentNode->MarkNeedSyncRenderTree(true);
1006 }
1007
UpdateLayoutPropertyFlag()1008 void UINode::UpdateLayoutPropertyFlag()
1009 {
1010 for (const auto& child : GetChildren()) {
1011 child->UpdateLayoutPropertyFlag();
1012 }
1013 }
1014
AdjustParentLayoutFlag(PropertyChangeFlag & flag)1015 void UINode::AdjustParentLayoutFlag(PropertyChangeFlag& flag)
1016 {
1017 for (const auto& child : GetChildren()) {
1018 child->AdjustParentLayoutFlag(flag);
1019 }
1020 }
1021
MarkDirtyNode(PropertyChangeFlag extraFlag)1022 void UINode::MarkDirtyNode(PropertyChangeFlag extraFlag)
1023 {
1024 for (const auto& child : GetChildren()) {
1025 child->MarkDirtyNode(extraFlag);
1026 }
1027 }
1028
MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)1029 void UINode::MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)
1030 {
1031 auto parent = parent_.Upgrade();
1032 if (parent) {
1033 parent->MarkNeedFrameFlushDirty(extraFlag);
1034 }
1035 }
1036
MarkNeedSyncRenderTree(bool needRebuild)1037 void UINode::MarkNeedSyncRenderTree(bool needRebuild)
1038 {
1039 auto parent = parent_.Upgrade();
1040 if (parent) {
1041 parent->MarkNeedSyncRenderTree(needRebuild);
1042 }
1043 }
1044
RebuildRenderContextTree()1045 void UINode::RebuildRenderContextTree()
1046 {
1047 auto parent = parent_.Upgrade();
1048 if (parent) {
1049 parent->RebuildRenderContextTree();
1050 }
1051 }
OnDetachFromMainTree(bool,PipelineContext *)1052 void UINode::OnDetachFromMainTree(bool, PipelineContext*) {}
1053
OnAttachToMainTree(bool)1054 void UINode::OnAttachToMainTree(bool)
1055 {
1056 useOffscreenProcess_ = false;
1057 if (isNodeAdapter_) {
1058 std::list<RefPtr<UINode>> nodes;
1059 RefPtr<UINode> uiNode = AceType::Claim<UINode>(this);
1060 BuilderUtils::GetBuilderNodes(uiNode, nodes);
1061 BuilderUtils::AddBuilderToParent(GetParent(), nodes);
1062 }
1063 }
1064
UpdateGeometryTransition()1065 void UINode::UpdateGeometryTransition()
1066 {
1067 auto children = GetChildren();
1068 for (const auto& child: children) {
1069 child->UpdateGeometryTransition();
1070 }
1071 }
1072
IsAutoFillContainerNode()1073 bool UINode::IsAutoFillContainerNode()
1074 {
1075 return tag_ == V2::PAGE_ETS_TAG || tag_ == V2::NAVDESTINATION_VIEW_ETS_TAG || tag_ == V2::DIALOG_ETS_TAG
1076 || tag_ == V2::SHEET_PAGE_TAG || tag_ == V2::MODAL_PAGE_TAG || tag_ == V2::POPUP_ETS_TAG;
1077 }
1078
DumpViewDataPageNodes(RefPtr<ViewDataWrap> viewDataWrap,bool skipSubAutoFillContainer,bool needsRecordData)1079 void UINode::DumpViewDataPageNodes(
1080 RefPtr<ViewDataWrap> viewDataWrap, bool skipSubAutoFillContainer, bool needsRecordData)
1081 {
1082 auto frameNode = AceType::DynamicCast<FrameNode>(this);
1083 if (frameNode && !frameNode->IsVisible()) {
1084 auto pattern = frameNode->GetPattern();
1085 if (pattern && !pattern->TriggerAutoSaveWhenInvisible()) {
1086 return;
1087 }
1088 }
1089 DumpViewDataPageNode(viewDataWrap, needsRecordData);
1090 for (const auto& item : GetChildren()) {
1091 if (!item) {
1092 continue;
1093 }
1094 if (skipSubAutoFillContainer && item->IsAutoFillContainerNode()) {
1095 continue;
1096 }
1097 item->DumpViewDataPageNodes(viewDataWrap, skipSubAutoFillContainer, needsRecordData);
1098 }
1099 }
1100
NeedRequestAutoSave()1101 bool UINode::NeedRequestAutoSave()
1102 {
1103 auto frameNode = AceType::DynamicCast<FrameNode>(this);
1104 if (frameNode && !frameNode->IsVisible()) {
1105 auto pattern = frameNode->GetPattern();
1106 if (pattern && !pattern->TriggerAutoSaveWhenInvisible()) {
1107 return false;
1108 }
1109 }
1110 if (CheckAutoSave()) {
1111 return true;
1112 }
1113 for (const auto& item : GetChildren()) {
1114 if (item->NeedRequestAutoSave()) {
1115 return true;
1116 }
1117 }
1118 return false;
1119 }
1120
DumpTree(int32_t depth,bool hasJson)1121 void UINode::DumpTree(int32_t depth, bool hasJson)
1122 {
1123 if (hasJson) {
1124 std::unique_ptr<JsonValue> json = JsonUtil::Create(true);
1125 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1126 children->Put("childSize", static_cast<int32_t>(GetChildren().size()));
1127 children->Put("ID", nodeId_);
1128 children->Put("Depth", depth_);
1129 children->Put("InstanceId", instanceId_);
1130 children->Put("AccessibilityId", accessibilityId_);
1131 if (IsDisappearing()) {
1132 children->Put("IsDisappearing", IsDisappearing());
1133 }
1134 DumpInfo(children);
1135 std::string key = isRoot_ ? tag_ : tag_ + "_" + std::to_string(nodeId_);
1136 json->Put(key.c_str(), children);
1137 std::string jsonstr = DumpLog::GetInstance().FormatDumpInfo(json->ToString(), depth);
1138 auto prefix = DumpLog::GetInstance().GetPrefix(depth);
1139 DumpLog::GetInstance().Append(prefix + jsonstr);
1140 } else {
1141 if (DumpLog::GetInstance().GetDumpFile()) {
1142 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
1143 DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(depth_)));
1144 DumpLog::GetInstance().AddDesc("InstanceId: " + std::to_string(instanceId_));
1145 DumpLog::GetInstance().AddDesc("AccessibilityId: " + std::to_string(accessibilityId_));
1146 if (IsDisappearing()) {
1147 DumpLog::GetInstance().AddDesc(
1148 std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
1149 }
1150 DumpInfo();
1151 DumpLog::GetInstance().Append(depth, tag_, static_cast<int32_t>(GetChildren().size()));
1152 }
1153 }
1154 if (!CheckVisibleOrActive()) {
1155 return;
1156 }
1157 if (GetTag() == V2::JS_LAZY_FOR_EACH_ETS_TAG || GetTag() == V2::JS_REPEAT_ETS_TAG) {
1158 for (const auto& item : GetChildrenForInspector(true)) {
1159 CHECK_NULL_CONTINUE(item);
1160 item->DumpTree(depth + 1, hasJson);
1161 }
1162 }
1163 for (const auto& item : GetChildren()) {
1164 item->DumpTree(depth + 1, hasJson);
1165 }
1166 for (const auto& [item, index, branch] : disappearingChildren_) {
1167 item->DumpTree(depth + 1, hasJson);
1168 }
1169 auto frameNode = AceType::DynamicCast<FrameNode>(this);
1170 if (frameNode && frameNode->GetOverlayNode()) {
1171 frameNode->GetOverlayNode()->DumpTree(depth + 1, hasJson);
1172 }
1173 }
1174
DumpTreeByComponentName(const std::string & name)1175 bool UINode::DumpTreeByComponentName(const std::string& name)
1176 {
1177 if (auto customNode = DynamicCast<CustomNode>(this)) {
1178 const std::string& tag = customNode->GetCustomTag();
1179 if (tag.size() >= name.size() && StringUtils::StartWith(tag, name)) {
1180 DumpTree(0);
1181 return true;
1182 }
1183 }
1184 for (const auto& item : GetChildren()) {
1185 if (item->DumpTreeByComponentName(name)) {
1186 return true;
1187 }
1188 }
1189 for (const auto& [item, index, branch] : disappearingChildren_) {
1190 if (item->DumpTreeByComponentName(name)) {
1191 return true;
1192 }
1193 }
1194 return false;
1195 }
1196
DumpTreeJsonForDiff(std::unique_ptr<JsonValue> & json)1197 void UINode::DumpTreeJsonForDiff(std::unique_ptr<JsonValue>& json)
1198 {
1199 auto currentNode = JsonUtil::Create(true);
1200 auto childrenNodeArray = JsonUtil::CreateArray(true);
1201 auto children = GetChildren();
1202 currentNode->Put("childSize", static_cast<int32_t>(children.size()));
1203 currentNode->Put("ID", nodeId_);
1204 currentNode->Put("Depth", depth_);
1205 currentNode->Put("InstanceId", instanceId_);
1206 currentNode->Put("AccessibilityId", accessibilityId_);
1207 if (IsDisappearing()) {
1208 currentNode->Put("IsDisappearing", IsDisappearing());
1209 }
1210 DumpInfo(currentNode);
1211 for (auto& child : children) {
1212 auto frameNode = AceType::DynamicCast<NG::FrameNode>(child);
1213 if (frameNode && layoutTags_.find(frameNode->GetTag()) != layoutTags_.end() && !frameNode->IsActive()) {
1214 continue;
1215 }
1216 auto childNode = JsonUtil::Create(true);
1217 child->DumpTreeJsonForDiff(childNode);
1218 childrenNodeArray->PutRef(std::move(childNode));
1219 }
1220 currentNode->PutRef("children", std::move(childrenNodeArray));
1221 std::string key = isRoot_ ? tag_ : tag_ + "_" + std::to_string(nodeId_);
1222 json->PutRef(key.c_str(), std::move(currentNode));
1223 }
1224
DumpSimplifyTree(int32_t depth,std::shared_ptr<JsonValue> & current)1225 void UINode::DumpSimplifyTree(int32_t depth, std::shared_ptr<JsonValue>& current)
1226 {
1227 current->Put("$type", tag_.c_str());
1228 current->Put("$ID", nodeId_);
1229 if (InstanceOf<CustomNode>(this)) {
1230 current->Put("type", "custom");
1231 } else {
1232 current->Put("type", "build-in");
1233 }
1234 auto nodeChildren = GetChildren();
1235 DumpSimplifyInfo(current);
1236 if (!CheckVisibleOrActive()) {
1237 return;
1238 }
1239 bool hasChildren = !nodeChildren.empty() || !disappearingChildren_.empty();
1240 if (hasChildren) {
1241 auto array = JsonUtil::CreateArray();
1242 if (!nodeChildren.empty()) {
1243 for (const auto& item : nodeChildren) {
1244 auto child = JsonUtil::CreateSharedPtrJson();
1245 item->DumpSimplifyTree(depth + 1, child);
1246 array->PutRef(std::move(child));
1247 }
1248 }
1249 if (!disappearingChildren_.empty()) {
1250 for (const auto& [item, index, branch] : disappearingChildren_) {
1251 auto child = JsonUtil::CreateSharedPtrJson();
1252 item->DumpSimplifyTree(depth + 1, child);
1253 array->PutRef(std::move(child));
1254 }
1255 }
1256 current->PutRef("$children", std::move(array));
1257 }
1258 }
1259
DumpTreeById(int32_t depth,const std::string & id,bool hasJson)1260 bool UINode::DumpTreeById(int32_t depth, const std::string& id, bool hasJson)
1261 {
1262 if (hasJson) {
1263 if ((id == propInspectorId_.value_or("") || id == std::to_string(nodeId_))) {
1264 std::unique_ptr<JsonValue> json = JsonUtil::Create(true);
1265 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1266 children->Put("childSize", static_cast<int32_t>(GetChildren().size()));
1267 children->Put("ID", nodeId_);
1268 children->Put("Depth", depth_);
1269 children->Put("IsDisappearing", IsDisappearing());
1270 DumpAdvanceInfo(children);
1271 json->Put(tag_.c_str(), children);
1272 DumpLog::GetInstance().PrintJson(json->ToString());
1273 return true;
1274 }
1275 } else {
1276 if (DumpLog::GetInstance().GetDumpFile() &&
1277 (id == propInspectorId_.value_or("") || id == std::to_string(nodeId_))) {
1278 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
1279 DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(depth_)));
1280 DumpLog::GetInstance().AddDesc(std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
1281 DumpAdvanceInfo();
1282 DumpLog::GetInstance().Print(depth, tag_, static_cast<int32_t>(GetChildren().size()));
1283 return true;
1284 }
1285 }
1286 for (const auto& item : GetChildren()) {
1287 if (item->DumpTreeById(depth + 1, id, hasJson)) {
1288 return true;
1289 }
1290 }
1291 for (const auto& [item, index, branch] : disappearingChildren_) {
1292 if (item->DumpTreeById(depth + 1, id, hasJson)) {
1293 return true;
1294 }
1295 }
1296 return false;
1297 }
1298
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)1299 void UINode::AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
1300 {
1301 for (const auto& child : children_) {
1302 if (!child->IsInDestroying()) {
1303 child->AdjustLayoutWrapperTree(parent, forceMeasure, forceLayout);
1304 }
1305 }
1306 }
1307
GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>> & visibleList)1308 void UINode::GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>>& visibleList)
1309 {
1310 for (const auto& child : GetChildren()) {
1311 child->OnGenerateOneDepthVisibleFrame(visibleList);
1312 }
1313 }
1314
GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)1315 void UINode::GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
1316 {
1317 if (disappearingChildren_.empty()) {
1318 // normal child
1319 for (const auto& child : GetChildren()) {
1320 child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
1321 }
1322 return;
1323 }
1324 // generate the merged list of children_ and disappearingChildren_
1325 auto allChildren = GetChildren();
1326 for (auto iter = disappearingChildren_.rbegin(); iter != disappearingChildren_.rend(); ++iter) {
1327 auto& [disappearingChild, index, _] = *iter;
1328 if (index >= allChildren.size()) {
1329 allChildren.emplace_back(disappearingChild);
1330 } else {
1331 auto insertIter = allChildren.begin();
1332 std::advance(insertIter, index);
1333 allChildren.insert(insertIter, disappearingChild);
1334 }
1335 disappearingChild->SetAncestor(WeakClaim(this));
1336 }
1337 for (const auto& child : allChildren) {
1338 child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
1339 }
1340 }
1341
GenerateOneDepthVisibleFrameWithOffset(std::list<RefPtr<FrameNode>> & visibleList,OffsetF & offset)1342 void UINode::GenerateOneDepthVisibleFrameWithOffset(
1343 std::list<RefPtr<FrameNode>>& visibleList, OffsetF& offset)
1344 {
1345 if (disappearingChildren_.empty()) {
1346 // normal child
1347 for (const auto& child : GetChildren()) {
1348 child->OnGenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
1349 }
1350 return;
1351 }
1352 // generate the merged list of children_ and disappearingChildren_
1353 auto allChildren = GetChildren();
1354 for (auto iter = disappearingChildren_.rbegin(); iter != disappearingChildren_.rend(); ++iter) {
1355 auto& [disappearingChild, index, _] = *iter;
1356 if (index >= allChildren.size()) {
1357 allChildren.emplace_back(disappearingChild);
1358 } else {
1359 auto insertIter = allChildren.begin();
1360 std::advance(insertIter, index);
1361 allChildren.insert(insertIter, disappearingChild);
1362 }
1363 disappearingChild->SetAncestor(WeakClaim(this));
1364 }
1365 for (const auto& child : allChildren) {
1366 child->OnGenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
1367 }
1368 }
1369
GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>> & visibleList)1370 void UINode::GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>>& visibleList)
1371 {
1372 for (const auto& child : GetChildren()) {
1373 child->OnGenerateOneDepthAllFrame(visibleList);
1374 }
1375 }
1376
GetContext() const1377 PipelineContext* UINode::GetContext() const
1378 {
1379 PipelineContext* context = nullptr;
1380 if (context_) {
1381 context = context_;
1382 } else {
1383 if (externalData_) {
1384 context = PipelineContext::GetCurrentContextPtrSafelyWithCheck();
1385 } else {
1386 context = PipelineContext::GetCurrentContextPtrSafely();
1387 }
1388 }
1389 return context;
1390 }
1391
GetAttachedContext() const1392 PipelineContext* UINode::GetAttachedContext() const
1393 {
1394 return context_;
1395 }
1396
GetContextWithCheck()1397 PipelineContext* UINode::GetContextWithCheck()
1398 {
1399 if (context_) {
1400 return context_;
1401 }
1402 return PipelineContext::GetCurrentContextPtrSafelyWithCheck();
1403 }
1404
GetContextRefPtr() const1405 RefPtr<PipelineContext> UINode::GetContextRefPtr() const
1406 {
1407 auto* context = GetContext();
1408 return Claim(context);
1409 }
1410
TouchTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,TouchTestResult & result,int32_t touchId,ResponseLinkResult & responseLinkResult,bool isDispatch)1411 HitTestResult UINode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1412 const PointF& parentRevertPoint, TouchRestrict& touchRestrict, TouchTestResult& result, int32_t touchId,
1413 ResponseLinkResult& responseLinkResult, bool isDispatch)
1414 {
1415 auto children = GetChildren();
1416 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1417 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1418 auto& child = *iter;
1419 auto hitResult = child->TouchTest(
1420 globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, result, touchId, responseLinkResult);
1421 if (hitResult == HitTestResult::STOP_BUBBLING) {
1422 return HitTestResult::STOP_BUBBLING;
1423 }
1424 if (hitResult == HitTestResult::BUBBLING) {
1425 hitTestResult = HitTestResult::BUBBLING;
1426 }
1427 }
1428 return hitTestResult;
1429 }
1430
MouseTest(const PointF & globalPoint,const PointF & parentLocalPoint,MouseTestResult & onMouseResult,MouseTestResult & onHoverResult,RefPtr<FrameNode> & hoverNode)1431 HitTestResult UINode::MouseTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1432 MouseTestResult& onMouseResult, MouseTestResult& onHoverResult, RefPtr<FrameNode>& hoverNode)
1433 {
1434 auto children = GetChildren();
1435 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1436 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1437 auto& child = *iter;
1438 auto hitResult = child->MouseTest(globalPoint, parentLocalPoint, onMouseResult, onHoverResult, hoverNode);
1439 if (hitResult == HitTestResult::STOP_BUBBLING) {
1440 return HitTestResult::STOP_BUBBLING;
1441 }
1442 if (hitResult == HitTestResult::BUBBLING) {
1443 hitTestResult = HitTestResult::BUBBLING;
1444 }
1445 }
1446 return hitTestResult;
1447 }
1448
AxisTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,AxisTestResult & onAxisResult)1449 HitTestResult UINode::AxisTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1450 const PointF& parentRevertPoint, TouchRestrict& touchRestrict, AxisTestResult& onAxisResult)
1451 {
1452 auto children = GetChildren();
1453 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1454 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1455 auto& child = *iter;
1456 auto hitResult = child->AxisTest(globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, onAxisResult);
1457 if (hitResult == HitTestResult::STOP_BUBBLING) {
1458 return HitTestResult::STOP_BUBBLING;
1459 }
1460 if (hitResult == HitTestResult::BUBBLING) {
1461 hitTestResult = HitTestResult::BUBBLING;
1462 }
1463 }
1464 return hitTestResult;
1465 }
1466
1467
FrameCount() const1468 int32_t UINode::FrameCount() const
1469 {
1470 return TotalChildCount();
1471 }
1472
TotalChildCount() const1473 int32_t UINode::TotalChildCount() const
1474 {
1475 int32_t count = 0;
1476 for (const auto& child : GetChildren()) {
1477 count += child->FrameCount();
1478 }
1479 return count;
1480 }
1481
CurrentFrameCount() const1482 int32_t UINode::CurrentFrameCount() const
1483 {
1484 int32_t count = 0;
1485 for (const auto& child : GetChildren()) {
1486 count += child->CurrentFrameCount();
1487 }
1488 return count;
1489 }
1490
GetChildIndexById(int32_t id)1491 int32_t UINode::GetChildIndexById(int32_t id)
1492 {
1493 int32_t pos = 0;
1494 auto children = GetChildren();
1495 auto iter = children.begin();
1496 while (iter != children.end()) {
1497 if (id == (*iter)->GetId()) {
1498 return pos;
1499 }
1500 pos++;
1501 iter++;
1502 }
1503 return -1;
1504 }
1505
CreateLayoutWrapper(bool forceMeasure,bool forceLayout)1506 RefPtr<LayoutWrapperNode> UINode::CreateLayoutWrapper(bool forceMeasure, bool forceLayout)
1507 {
1508 if (GetChildren().empty()) {
1509 return nullptr;
1510 }
1511
1512 auto child = GetChildren().front();
1513 while (!InstanceOf<FrameNode>(child)) {
1514 auto children = child->GetChildren();
1515 if (children.empty()) {
1516 return nullptr;
1517 }
1518
1519 child = children.front();
1520 }
1521
1522 auto frameChild = DynamicCast<FrameNode>(child);
1523 return frameChild ? frameChild->CreateLayoutWrapper(forceMeasure, forceLayout) : nullptr;
1524 }
1525
RenderCustomChild(int64_t deadline)1526 bool UINode::RenderCustomChild(int64_t deadline)
1527 {
1528 for (const auto& child : GetChildren()) {
1529 if (child && !child->RenderCustomChild(deadline)) {
1530 return false;
1531 }
1532 }
1533 return true;
1534 }
1535
Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)1536 void UINode::Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)
1537 {
1538 ACE_LAYOUT_TRACE_BEGIN("Build[%s][self:%d][parent:%d][key:%s]", tag_.c_str(), nodeId_,
1539 GetParent() ? GetParent()->GetId() : 0, GetInspectorIdValue("").c_str());
1540 std::vector<RefPtr<UINode>> children;
1541 children.reserve(GetChildren().size());
1542 for (const auto& child : GetChildren()) {
1543 children.push_back(child);
1544 }
1545 for (const auto& child : children) {
1546 if (InstanceOf<CustomNode>(child)) {
1547 auto custom = DynamicCast<CustomNode>(child);
1548 if (custom->HasExtraInfo()) {
1549 if (!extraInfos) {
1550 extraInfos = std::make_shared<std::list<ExtraInfo>>();
1551 }
1552 extraInfos->emplace_front(custom->GetExtraInfo());
1553 custom->Build(extraInfos);
1554 extraInfos->pop_front();
1555 } else {
1556 custom->Build(extraInfos);
1557 }
1558 } else {
1559 child->Build(extraInfos);
1560 }
1561 }
1562 ACE_LAYOUT_TRACE_END()
1563 }
1564
CreateExportTextureInfoIfNeeded()1565 void UINode::CreateExportTextureInfoIfNeeded()
1566 {
1567 if (!exportTextureInfo_) {
1568 exportTextureInfo_ = MakeRefPtr<ExportTextureInfo>();
1569 }
1570 }
1571
IsNeedExportTexture() const1572 bool UINode::IsNeedExportTexture() const
1573 {
1574 return exportTextureInfo_ && exportTextureInfo_->GetCurrentRenderType() == NodeRenderType::RENDER_TYPE_TEXTURE;
1575 }
1576
SetActive(bool active,bool needRebuildRenderContext)1577 void UINode::SetActive(bool active, bool needRebuildRenderContext)
1578 {
1579 for (const auto& child : GetChildren()) {
1580 child->SetActive(active, needRebuildRenderContext);
1581 }
1582 }
1583
SetJSViewActive(bool active,bool isLazyForEachNode,bool isReuse)1584 void UINode::SetJSViewActive(bool active, bool isLazyForEachNode, bool isReuse)
1585 {
1586 for (const auto& child : GetChildren()) {
1587 auto customNode = AceType::DynamicCast<CustomNode>(child);
1588 // do not need to recursive here, stateMgmt will recursive all children when set active
1589 if (customNode && customNode->GetIsV2() && isLazyForEachNode) {
1590 return;
1591 }
1592 if (customNode) {
1593 customNode->SetJSViewActive(active, isLazyForEachNode, isReuse);
1594 continue;
1595 }
1596 child->SetJSViewActive(active, isLazyForEachNode, isReuse);
1597 }
1598 }
1599
TryVisibleChangeOnDescendant(VisibleType preVisibility,VisibleType currentVisibility)1600 void UINode::TryVisibleChangeOnDescendant(VisibleType preVisibility, VisibleType currentVisibility)
1601 {
1602 UpdateChildrenVisible(preVisibility, currentVisibility);
1603 }
1604
UpdateChildrenVisible(VisibleType preVisibility,VisibleType currentVisibility) const1605 void UINode::UpdateChildrenVisible(VisibleType preVisibility, VisibleType currentVisibility) const
1606 {
1607 for (const auto& child : GetChildren()) {
1608 child->TryVisibleChangeOnDescendant(preVisibility, currentVisibility);
1609 }
1610 }
1611
OnRecycle()1612 void UINode::OnRecycle()
1613 {
1614 for (const auto& child : GetChildren()) {
1615 child->OnRecycle();
1616 }
1617 }
1618
NotifyColorModeChange(uint32_t colorMode)1619 void UINode::NotifyColorModeChange(uint32_t colorMode)
1620 {
1621 if (CheckShouldClearCache()) {
1622 auto customNode = DynamicCast<CustomNode>(this);
1623 if (customNode) {
1624 ContainerScope scope(instanceId_);
1625 ACE_LAYOUT_TRACE_BEGIN("UINode %d %s is customnode %d",
1626 nodeId_, tag_.c_str(), customNode ? true : false);
1627 customNode->FireClearAllRecycleFunc();
1628 SetShouldClearCache(false);
1629 ACE_LAYOUT_TRACE_END()
1630 }
1631 }
1632 for (const auto& child : GetChildren()) {
1633 child->SetShouldClearCache(CheckShouldClearCache());
1634 child->SetRerenderable(GetRerenderable());
1635 child->SetMeasureAnyway(CheckMeasureAnyway());
1636 if (!AceType::DynamicCast<FrameNode>(child)) {
1637 child->SetDarkMode(CheckIsDarkMode());
1638 }
1639 child->NotifyColorModeChange(colorMode);
1640 }
1641 }
1642
OnReuse()1643 void UINode::OnReuse()
1644 {
1645 for (const auto& child : GetChildren()) {
1646 child->OnReuse();
1647 }
1648 }
1649
GetChildFlatIndex(int32_t id)1650 std::pair<bool, int32_t> UINode::GetChildFlatIndex(int32_t id)
1651 {
1652 if (nodeId_ == id) {
1653 return { true, 0 };
1654 }
1655
1656 const auto& node = ElementRegister::GetInstance()->GetUINodeById(id);
1657 if (!node) {
1658 return { false, 0 };
1659 }
1660
1661 if (node && (node->GetTag() == tag_)) {
1662 return { false, 1 };
1663 }
1664
1665 int32_t count = 0;
1666 for (const auto& child : GetChildren()) {
1667 auto res = child->GetChildFlatIndex(id);
1668 if (res.first) {
1669 return { true, count + res.second };
1670 }
1671 count += res.second;
1672 }
1673 return { false, count };
1674 }
1675
MarkRemoving()1676 bool UINode::MarkRemoving()
1677 {
1678 bool pendingRemove = false;
1679 isRemoving_ = true;
1680 const auto children = GetChildren();
1681 for (const auto& child : children) {
1682 pendingRemove = child->MarkRemoving() || pendingRemove;
1683 }
1684 return pendingRemove;
1685 }
1686
SetChildrenInDestroying()1687 void UINode::SetChildrenInDestroying()
1688 {
1689 auto children = GetChildren();
1690 if (children.empty()) {
1691 return;
1692 }
1693
1694 for (const auto& child : children) {
1695 if (!child) {
1696 continue;
1697 }
1698 child->SetChildrenInDestroying();
1699 child->SetInDestroying();
1700 }
1701 }
1702
AddDisappearingChild(const RefPtr<UINode> & child,uint32_t index,int32_t branchId)1703 void UINode::AddDisappearingChild(const RefPtr<UINode>& child, uint32_t index, int32_t branchId)
1704 {
1705 if (child->isDisappearing_) {
1706 // if child is already disappearing, remove it from disappearingChildren_ first
1707 auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
1708 [child](const auto& tup) { return std::get<0>(tup) == child; });
1709 if (it != disappearingChildren_.end()) {
1710 disappearingChildren_.erase(it);
1711 }
1712 } else {
1713 // mark child as disappearing before adding to disappearingChildren_
1714 child->isDisappearing_ = true;
1715 }
1716 if (DetectLoop(child, Claim(this))) {
1717 return;
1718 }
1719 disappearingChildren_.emplace_back(child, index, branchId);
1720 }
1721
RemoveDisappearingChild(const RefPtr<UINode> & child)1722 bool UINode::RemoveDisappearingChild(const RefPtr<UINode>& child)
1723 {
1724 // quick reject
1725 if (!child || !child->isDisappearing_) {
1726 return false;
1727 }
1728 auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
1729 [child](const auto& tup) { return std::get<0>(tup) == child; });
1730 if (it == disappearingChildren_.end()) {
1731 return false;
1732 }
1733 disappearingChildren_.erase(it);
1734 child->isDisappearing_ = false;
1735 return true;
1736 }
1737
OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)1738 void UINode::OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
1739 {
1740 GenerateOneDepthVisibleFrameWithTransition(visibleList);
1741 }
1742
OnGenerateOneDepthVisibleFrameWithOffset(std::list<RefPtr<FrameNode>> & visibleList,OffsetF & offset)1743 void UINode::OnGenerateOneDepthVisibleFrameWithOffset(
1744 std::list<RefPtr<FrameNode>>& visibleList, OffsetF& offset)
1745 {
1746 GenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
1747 }
1748
RemoveImmediately() const1749 bool UINode::RemoveImmediately() const
1750 {
1751 auto children = GetChildren();
1752 return std::all_of(
1753 children.begin(), children.end(), [](const auto& child) { return child->RemoveImmediately(); }) &&
1754 std::all_of(disappearingChildren_.begin(), disappearingChildren_.end(),
1755 [](const auto& tup) { return std::get<0>(tup)->RemoveImmediately(); });
1756 }
1757
GetPerformanceCheckData(PerformanceCheckNodeMap & nodeMap)1758 void UINode::GetPerformanceCheckData(PerformanceCheckNodeMap& nodeMap)
1759 {
1760 auto parent = GetParent();
1761 auto children = GetChildren();
1762 if (parent && parent->GetTag() == V2::JS_FOR_EACH_ETS_TAG) {
1763 // At this point, all of the children_
1764 // belong to the child nodes of syntaxItem
1765 for (const auto& child : children) {
1766 if (child->GetTag() == V2::COMMON_VIEW_ETS_TAG) {
1767 auto grandChildren = child->GetChildren();
1768 if (!grandChildren.empty()) {
1769 auto begin = grandChildren.begin();
1770 (*begin)->SetForeachItem();
1771 }
1772 } else {
1773 child->SetForeachItem();
1774 }
1775 }
1776 }
1777
1778 if (tag_ == V2::COMMON_VIEW_ETS_TAG) {
1779 if (!children.empty()) {
1780 auto begin = children.begin();
1781 nodeInfo_->nodeTag = (*begin)->GetCustomTag();
1782 }
1783 } else {
1784 nodeInfo_->nodeTag = GetCustomTag();
1785 }
1786
1787 nodeInfo_->pageDepth = depth_;
1788 nodeInfo_->childrenSize = children.size();
1789 if (isBuildByJS_) {
1790 nodeMap.insert({ nodeId_, *(nodeInfo_) });
1791 }
1792 for (const auto& child : children) {
1793 // Recursively traverse the child nodes of each node
1794 child->GetPerformanceCheckData(nodeMap);
1795 }
1796 }
1797
GetDisappearingChildById(const std::string & id,int32_t branchId) const1798 RefPtr<UINode> UINode::GetDisappearingChildById(const std::string& id, int32_t branchId) const
1799 {
1800 if (id.empty()) {
1801 return nullptr;
1802 }
1803 for (auto& [node, index, branch] : disappearingChildren_) {
1804 if (node->GetInspectorIdValue("") == id && branch == branchId) {
1805 return node;
1806 }
1807 }
1808 return nullptr;
1809 }
1810
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)1811 RefPtr<UINode> UINode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
1812 {
1813 for (const auto& child : GetChildren()) {
1814 uint32_t count = static_cast<uint32_t>(child->FrameCount());
1815 if (count > index) {
1816 return child->GetFrameChildByIndex(index, needBuild, isCache, addToRenderTree);
1817 }
1818 index -= count;
1819 }
1820 return nullptr;
1821 }
1822
GetFrameChildByIndexWithoutExpanded(uint32_t index)1823 RefPtr<UINode> UINode::GetFrameChildByIndexWithoutExpanded(uint32_t index)
1824 {
1825 for (const auto& child : GetChildren()) {
1826 uint32_t count = static_cast<uint32_t>(child->CurrentFrameCount());
1827 if (count > index) {
1828 return child->GetFrameChildByIndexWithoutExpanded(index);
1829 }
1830 index -= count;
1831 }
1832 return nullptr;
1833 }
1834
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)1835 int32_t UINode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
1836 {
1837 int32_t index = 0;
1838 for (const auto& child : GetChildren()) {
1839 if (InstanceOf<FrameNode>(child)) {
1840 if (child == node) {
1841 return index;
1842 } else {
1843 index++;
1844 continue;
1845 }
1846 }
1847 int32_t childIndex = child->GetFrameNodeIndex(node, isExpanded);
1848 if (childIndex >= 0) {
1849 return index + childIndex;
1850 }
1851 index += isExpanded ? child->FrameCount() : child->CurrentFrameCount();
1852 }
1853 return -1;
1854 }
1855
DoRemoveChildInRenderTree(uint32_t index,bool isAll)1856 void UINode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
1857 {
1858 if (isAll) {
1859 for (const auto& child : children_) {
1860 child->DoRemoveChildInRenderTree(index, isAll);
1861 }
1862 return;
1863 }
1864 for (const auto& child : children_) {
1865 uint32_t count = static_cast<uint32_t>(child->FrameCount());
1866 if (count > index) {
1867 return child->DoRemoveChildInRenderTree(index);
1868 }
1869 index -= count;
1870 }
1871 }
1872
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)1873 void UINode::DoSetActiveChildRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
1874 {
1875 for (const auto& child : children_) {
1876 uint32_t count = static_cast<uint32_t>(child->FrameCount());
1877 child->DoSetActiveChildRange(start, end, cacheStart, cacheEnd, showCache);
1878 start -= static_cast<int32_t>(count);
1879 end -= static_cast<int32_t>(count);
1880 }
1881 }
1882
OnSetCacheCount(int32_t cacheCount,const std::optional<LayoutConstraintF> & itemConstraint)1883 void UINode::OnSetCacheCount(int32_t cacheCount, const std::optional<LayoutConstraintF>& itemConstraint)
1884 {
1885 for (const auto& child : GetChildren()) {
1886 child->OnSetCacheCount(cacheCount, itemConstraint);
1887 }
1888 }
1889
GetCurrentCustomNodeInfo()1890 std::string UINode::GetCurrentCustomNodeInfo()
1891 {
1892 auto parent = AceType::Claim(this);
1893 std::string extraInfo;
1894 while (parent) {
1895 if (InstanceOf<CustomNode>(parent)) {
1896 auto custom = DynamicCast<CustomNode>(parent);
1897 auto list = custom->GetExtraInfos();
1898 for (const auto& child : list) {
1899 extraInfo.append(" ")
1900 .append("at (")
1901 .append(child.page)
1902 .append(":")
1903 .append(std::to_string(child.line))
1904 .append(":")
1905 .append(std::to_string(child.col))
1906 .append(")\n");
1907 }
1908 break;
1909 }
1910 parent = parent->GetParent();
1911 }
1912 return extraInfo;
1913 }
1914
GenerateAccessibilityId()1915 int64_t UINode::GenerateAccessibilityId()
1916 {
1917 return currentAccessibilityId_++;
1918 }
1919
GetNodeStatus() const1920 NodeStatus UINode::GetNodeStatus() const
1921 {
1922 return nodeStatus_;
1923 }
1924
SetParentLayoutConstraint(const SizeF & size) const1925 bool UINode::SetParentLayoutConstraint(const SizeF& size) const
1926 {
1927 auto children = GetChildren();
1928 return std::any_of(children.begin(), children.end(),
1929 [size](const RefPtr<UINode>& child) { return child->SetParentLayoutConstraint(size); });
1930 }
1931
UpdateNodeStatus(NodeStatus nodeStatus)1932 void UINode::UpdateNodeStatus(NodeStatus nodeStatus)
1933 {
1934 if (nodeStatus_ == nodeStatus) {
1935 return;
1936 }
1937 nodeStatus_ = nodeStatus;
1938 OnAttachToBuilderNode(nodeStatus_);
1939 for (const auto& child : children_) {
1940 child->UpdateNodeStatus(nodeStatus_);
1941 }
1942 }
1943
SetIsRootBuilderNode(bool isRootBuilderNode)1944 void UINode::SetIsRootBuilderNode(bool isRootBuilderNode)
1945 {
1946 isRootBuilderNode_ = isRootBuilderNode;
1947 if (isRootBuilderNode) {
1948 jsBuilderNodeId_ = nodeId_;
1949 } else {
1950 jsBuilderNodeId_ = -1;
1951 }
1952 }
1953
GetIsRootBuilderNode() const1954 bool UINode::GetIsRootBuilderNode() const
1955 {
1956 return isRootBuilderNode_;
1957 }
1958
1959 // Collects all the child elements of "children" in a recursive manner
1960 // Fills the "removedElmtId" list and the "reservedElmtId" list with the collected child elements
CollectCleanedChildren(const std::list<RefPtr<UINode>> & children,std::list<int32_t> & removedElmtId,std::list<int32_t> & reservedElmtId,bool isEntry)1961 void UINode::CollectCleanedChildren(const std::list<RefPtr<UINode>>& children, std::list<int32_t>& removedElmtId,
1962 std::list<int32_t>& reservedElmtId, bool isEntry)
1963 {
1964 auto greatOrEqualApi13 = GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN);
1965 for (auto const& child : children) {
1966 bool needByTransition = child->IsDisappearing();
1967 if (greatOrEqualApi13) {
1968 needByTransition = isEntry && child->IsDisappearing() && child->GetInspectorIdValue("") != "";
1969 }
1970
1971 if (!needByTransition && child->GetTag() != V2::RECYCLE_VIEW_ETS_TAG && !child->GetIsRootBuilderNode()) {
1972 removedElmtId.emplace_back(child->GetId());
1973 if (child->GetTag() != V2::JS_VIEW_ETS_TAG) {
1974 CollectCleanedChildren(child->GetChildren(), removedElmtId, reservedElmtId, false);
1975 }
1976 } else if (needByTransition && greatOrEqualApi13) {
1977 child->CollectReservedChildren(reservedElmtId);
1978 }
1979 if (isEntry) {
1980 child->SetAncestor(nullptr);
1981 }
1982 }
1983 if (isEntry) {
1984 children_.clear();
1985 }
1986 }
1987
CollectReservedChildren(std::list<int32_t> & reservedElmtId)1988 void UINode::CollectReservedChildren(std::list<int32_t>& reservedElmtId)
1989 {
1990 reservedElmtId.emplace_back(nodeId_);
1991 if (tag_ == V2::JS_VIEW_ETS_TAG) {
1992 SetJSViewActive(false);
1993 } else {
1994 for (auto const& child : GetChildren()) {
1995 child->CollectReservedChildren(reservedElmtId);
1996 }
1997 }
1998 }
1999
2000 // Collects all the child elements of "children" in a recursive manner
2001 // Fills the "removedElmtId" list with the collected child elements
CollectRemovedChildren(const std::list<RefPtr<UINode>> & children,std::list<int32_t> & removedElmtId,bool isEntry)2002 void UINode::CollectRemovedChildren(const std::list<RefPtr<UINode>>& children,
2003 std::list<int32_t>& removedElmtId, bool isEntry)
2004 {
2005 auto greatOrEqualApi13 = GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN);
2006 for (auto const& child : children) {
2007 bool needByTransition = child->IsDisappearing();
2008 if (greatOrEqualApi13) {
2009 needByTransition = isEntry && child->IsDisappearing() && child->GetInspectorIdValue("") != "";
2010 }
2011 if (!needByTransition && child->GetTag() != V2::RECYCLE_VIEW_ETS_TAG && !child->GetIsRootBuilderNode()) {
2012 CollectRemovedChild(child, removedElmtId);
2013 }
2014 if (isEntry) {
2015 child->SetAncestor(nullptr);
2016 }
2017 }
2018 if (isEntry) {
2019 children_.clear();
2020 }
2021 }
2022
CollectRemovedChild(const RefPtr<UINode> & child,std::list<int32_t> & removedElmtId)2023 void UINode::CollectRemovedChild(const RefPtr<UINode>& child, std::list<int32_t>& removedElmtId)
2024 {
2025 removedElmtId.emplace_back(child->GetId());
2026 child->OnCollectRemoved();
2027 // Fetch all the child elementIDs recursively
2028 if (child->GetTag() != V2::JS_VIEW_ETS_TAG) {
2029 // add CustomNode but do not recurse into its children
2030 // add node create by BuilderNode do not recurse into its children
2031 CollectRemovedChildren(child->GetChildren(), removedElmtId, false);
2032 }
2033 }
2034
PaintDebugBoundaryTreeAll(bool flag)2035 void UINode::PaintDebugBoundaryTreeAll(bool flag)
2036 {
2037 PaintDebugBoundary(flag);
2038 for (const auto& child : GetChildren()) {
2039 child->PaintDebugBoundaryTreeAll(flag);
2040 }
2041 }
2042
GetPageNodeCountAndDepth(int32_t * count,int32_t * depth)2043 void UINode::GetPageNodeCountAndDepth(int32_t* count, int32_t* depth)
2044 {
2045 ACE_SCOPED_TRACE("GetPageNodeCountAndDepth");
2046 auto children = GetChildren();
2047 if (*depth < depth_) {
2048 *depth = depth_;
2049 }
2050 if (InstanceOf<FrameNode>(this)) {
2051 (*count)++;
2052 }
2053
2054 for (const auto& child : children) {
2055 child->GetPageNodeCountAndDepth(count, depth);
2056 }
2057 }
2058
DFSAllChild(const RefPtr<UINode> & root,std::vector<RefPtr<UINode>> & res)2059 void UINode::DFSAllChild(const RefPtr<UINode>& root, std::vector<RefPtr<UINode>>& res)
2060 {
2061 if (root->GetChildren().empty()) {
2062 res.emplace_back(root);
2063 }
2064 for (const auto& child : root->GetChildren()) {
2065 DFSAllChild(child, res);
2066 }
2067 }
2068
IsContextTransparent()2069 bool UINode::IsContextTransparent()
2070 {
2071 for (const auto& item : GetChildren()) {
2072 if (!item->IsContextTransparent()) {
2073 return false;
2074 }
2075 }
2076 return true;
2077 }
2078
GetInspectorValue()2079 void UINode::GetInspectorValue()
2080 {
2081 for (const auto& item : GetChildren()) {
2082 item->GetInspectorValue();
2083 }
2084 }
2085
ClearSubtreeLayoutAlgorithm(bool includeSelf,bool clearEntireTree)2086 void UINode::ClearSubtreeLayoutAlgorithm(bool includeSelf, bool clearEntireTree)
2087 {
2088 for (const auto& child : GetChildren()) {
2089 child->ClearSubtreeLayoutAlgorithm(includeSelf, clearEntireTree);
2090 }
2091 }
2092
NotifyWebPattern(bool isRegister)2093 void UINode::NotifyWebPattern(bool isRegister)
2094 {
2095 for (const auto& item : GetChildren()) {
2096 item->NotifyWebPattern(isRegister);
2097 }
2098 }
2099
GetContainerComponentText(std::u16string & text)2100 void UINode::GetContainerComponentText(std::u16string& text)
2101 {
2102 for (const auto& child : GetChildren()) {
2103 if (InstanceOf<FrameNode>(child) && child->GetTag() == V2::TEXT_ETS_TAG) {
2104 auto frameChild = DynamicCast<FrameNode>(child);
2105 auto pattern = frameChild->GetPattern();
2106 CHECK_NULL_VOID(pattern);
2107 auto layoutProperty = pattern->GetLayoutProperty<TextLayoutProperty>();
2108 CHECK_NULL_VOID(layoutProperty);
2109 text = layoutProperty->GetContent().value_or(u"");
2110 break;
2111 }
2112 child->GetContainerComponentText(text);
2113 }
2114 }
2115
CalcAbsPosition(int32_t changeIdx,int64_t id) const2116 int32_t UINode::CalcAbsPosition(int32_t changeIdx, int64_t id) const
2117 {
2118 int32_t updateFrom = 0;
2119 for (const auto& child : GetChildren()) {
2120 if (child->GetAccessibilityId() == id) {
2121 updateFrom += changeIdx;
2122 break;
2123 }
2124 int32_t count = child->FrameCount();
2125 updateFrom += count;
2126 }
2127 return updateFrom;
2128 }
2129
NotifyChange(int32_t changeIdx,int32_t count,int64_t id,NotificationType notificationType)2130 void UINode::NotifyChange(int32_t changeIdx, int32_t count, int64_t id, NotificationType notificationType)
2131 {
2132 int32_t updateFrom = CalcAbsPosition(changeIdx, id);
2133 auto accessibilityId = accessibilityId_;
2134 auto parent = GetParent();
2135 if (parent) {
2136 parent->NotifyChange(updateFrom, count, accessibilityId, notificationType);
2137 }
2138 }
2139
SetParent(const WeakPtr<UINode> & parent,bool needDetect)2140 void UINode::SetParent(const WeakPtr<UINode>& parent, bool needDetect)
2141 {
2142 auto current = parent.Upgrade();
2143 CHECK_NULL_VOID(current);
2144 if (needDetect && DetectLoop(Claim(this), current)) {
2145 return;
2146 }
2147 parent_ = parent;
2148 ancestor_ = parent;
2149 }
2150
GetThemeScopeId() const2151 int32_t UINode::GetThemeScopeId() const
2152 {
2153 return themeScopeId_;
2154 }
2155
SetThemeScopeId(int32_t themeScopeId)2156 void UINode::SetThemeScopeId(int32_t themeScopeId)
2157 {
2158 LOGD("WithTheme SetThemeScopeId %{public}d", themeScopeId);
2159 themeScopeId_ = themeScopeId;
2160 auto children = GetChildren();
2161 for (const auto& child : children) {
2162 if (!child) {
2163 continue;
2164 }
2165 child->SetThemeScopeId(themeScopeId);
2166 }
2167 }
2168
UpdateThemeScopeId(int32_t themeScopeId)2169 void UINode::UpdateThemeScopeId(int32_t themeScopeId)
2170 {
2171 if (GetThemeScopeId() == themeScopeId) {
2172 return;
2173 }
2174 LOGD("WithTheme UpdateThemeScopeId old:%{public}d new:%{public}d", GetThemeScopeId(), themeScopeId);
2175 themeScopeId_ = themeScopeId;
2176 OnThemeScopeUpdate(themeScopeId);
2177 auto children = GetChildren();
2178 for (const auto& child : children) {
2179 if (!child) {
2180 continue;
2181 }
2182 child->UpdateThemeScopeId(themeScopeId);
2183 }
2184 }
2185
UpdateThemeScopeUpdate(int32_t themeScopeId)2186 void UINode::UpdateThemeScopeUpdate(int32_t themeScopeId)
2187 {
2188 if (GetThemeScopeId() != themeScopeId) {
2189 return;
2190 }
2191 OnThemeScopeUpdate(themeScopeId);
2192 if (needCallChildrenUpdate_) {
2193 auto children = GetChildren();
2194 for (const auto& child : children) {
2195 if (!child) {
2196 continue;
2197 }
2198 child->UpdateThemeScopeUpdate(themeScopeId);
2199 }
2200 }
2201 }
2202
AllowUseParentTheme(bool isAllow)2203 void UINode::AllowUseParentTheme(bool isAllow)
2204 {
2205 isAllowUseParentTheme_ = isAllow;
2206 }
2207
IsAllowUseParentTheme() const2208 bool UINode::IsAllowUseParentTheme() const
2209 {
2210 return isAllowUseParentTheme_;
2211 }
2212
GetLocalColorMode() const2213 ColorMode UINode::GetLocalColorMode() const
2214 {
2215 auto theme = TokenThemeStorage::GetInstance()->GetTheme(GetThemeScopeId());
2216 return theme ? theme->GetColorMode() : ColorMode::COLOR_MODE_UNDEFINED;
2217 }
2218
SetAllowReusableV2Descendant(bool allow)2219 void UINode::SetAllowReusableV2Descendant(bool allow)
2220 {
2221 allowReusableV2Descendant_ = allow;
2222 }
2223
IsAllowReusableV2Descendant() const2224 bool UINode::IsAllowReusableV2Descendant() const
2225 {
2226 return allowReusableV2Descendant_;
2227 }
2228
SetDestroying(bool isDestroying,bool cleanStatus)2229 void UINode::SetDestroying(bool isDestroying, bool cleanStatus)
2230 {
2231 if (isInDestroying_ == isDestroying) {
2232 return;
2233 }
2234
2235 isInDestroying_ = isDestroying;
2236 for (const auto& child : GetChildren()) {
2237 if (child->IsReusableNode()) {
2238 child->SetDestroying(isDestroying, false);
2239 } else {
2240 child->SetDestroying(isDestroying, cleanStatus);
2241 }
2242 }
2243 // add customnode to pipiline when state change, destroy them next vsync
2244 OnDestroyingStateChange(isDestroying, cleanStatus);
2245 }
2246
HasSkipNode()2247 bool UINode::HasSkipNode()
2248 {
2249 for (const auto& child : children_) {
2250 if (child->GetTag() == V2::WEB_ETS_TAG) {
2251 return true;
2252 }
2253
2254 if (child->HasSkipNode()) {
2255 return true;
2256 }
2257 }
2258 return false;
2259 }
2260
ProcessIsInDestroyingForReuseableNode(const RefPtr<UINode> & child)2261 void UINode::ProcessIsInDestroyingForReuseableNode(const RefPtr<UINode>& child)
2262 {
2263 if (!child || !child->IsReusableNode()) {
2264 return;
2265 }
2266 if (!IsInDestroying() && child->IsInDestroying()) {
2267 child->SetDestroying(false, false);
2268 }
2269 }
2270
GreatOrEqualAPITargetVersion(PlatformVersion version) const2271 bool UINode::GreatOrEqualAPITargetVersion(PlatformVersion version) const
2272 {
2273 if (!context_ || context_->GetApiTargetVersion() == 0) {
2274 return apiVersion_ >= static_cast<int32_t>(version);
2275 }
2276 return context_->GreatOrEqualAPITargetVersion(version);
2277 }
2278
LessThanAPITargetVersion(PlatformVersion version) const2279 bool UINode::LessThanAPITargetVersion(PlatformVersion version) const
2280 {
2281 if (!context_ || context_->GetApiTargetVersion() == 0) {
2282 return apiVersion_ < static_cast<int32_t>(version);
2283 }
2284 return context_->LessThanAPITargetVersion(version);
2285 }
2286
UpdateDrawChildObserver(const RefPtr<UINode> & child)2287 void UINode::UpdateDrawChildObserver(const RefPtr<UINode>& child)
2288 {
2289 if (GetInspectorId().has_value()) {
2290 auto pipeline = GetContextRefPtr();
2291 CHECK_NULL_VOID(pipeline);
2292 auto front = pipeline->GetFrontend();
2293 if (front) {
2294 auto hasDrawChildCallback = front->IsDrawChildrenCallbackFuncExist(GetInspectorId().value_or(""));
2295 if (hasDrawChildCallback) {
2296 child->SetObserverParentForDrawChildren(Claim(this));
2297 }
2298 }
2299 }
2300 if (IsObservedByDrawChildren()) {
2301 auto parentForObserverDrawChildren = GetObserverParentForDrawChildren();
2302 if (parentForObserverDrawChildren) {
2303 child->SetObserverParentForDrawChildren(parentForObserverDrawChildren);
2304 }
2305 }
2306 }
2307
SetObserverParentForDrawChildren(const RefPtr<UINode> & parent)2308 void UINode::SetObserverParentForDrawChildren(const RefPtr<UINode>& parent)
2309 {
2310 CHECK_NULL_VOID(parent);
2311 isObservedByDrawChildren_ = true;
2312 drawChildrenParent_ = parent;
2313 for (const auto& child : GetChildren()) {
2314 child->SetObserverParentForDrawChildren(parent);
2315 }
2316 }
2317
GetAncestor() const2318 RefPtr<UINode> UINode::GetAncestor() const
2319 {
2320 return ancestor_.Upgrade();
2321 }
2322
SetAncestor(const WeakPtr<UINode> & parent)2323 void UINode::SetAncestor(const WeakPtr<UINode>& parent)
2324 {
2325 ancestor_ = parent;
2326 }
2327
FindTopNavDestination(RefPtr<FrameNode> & result)2328 void UINode::FindTopNavDestination(RefPtr<FrameNode>& result)
2329 {
2330 auto currentNode = AceType::DynamicCast<FrameNode>(this);
2331 if (currentNode && currentNode->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
2332 auto navigationGroupNode = AceType::DynamicCast<NG::NavigationGroupNode>(currentNode);
2333 CHECK_NULL_VOID(navigationGroupNode);
2334 result = navigationGroupNode->GetTopDestination();
2335 return;
2336 }
2337 for (const auto& item : GetChildren()) {
2338 item->FindTopNavDestination(result);
2339 if (result) {
2340 return;
2341 }
2342 }
2343 }
2344 } // namespace OHOS::Ace::NG
2345