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