• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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