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 <memory>
18 
19 #include "base/geometry/ng/point_t.h"
20 #include "base/log/ace_checker.h"
21 #include "base/log/ace_performance_check.h"
22 #include "base/log/ace_trace.h"
23 #include "base/log/dump_log.h"
24 #include "base/memory/referenced.h"
25 #include "base/utils/system_properties.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/engine_helper.h"
28 #include "core/common/container.h"
29 #include "core/components_ng/base/view_stack_processor.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 #include "core/components_ng/property/layout_constraint.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline/base/element_register.h"
34 #include "core/pipeline_ng/pipeline_context.h"
35 
36 namespace OHOS::Ace::NG {
37 
38 thread_local int64_t currentAccessibilityId_ = 0;
39 
UINode(const std::string & tag,int32_t nodeId,bool isRoot)40 UINode::UINode(const std::string& tag, int32_t nodeId, bool isRoot)
41     : tag_(tag), nodeId_(nodeId), accessibilityId_(currentAccessibilityId_++), isRoot_(isRoot)
42 {
43     if (AceChecker::IsPerformanceCheckEnabled()) {
44         auto pos = EngineHelper::GetPositionOnJsCode();
45         nodeInfo_ = std::make_unique<PerformanceCheckNode>();
46         nodeInfo_->codeRow = pos.first;
47         nodeInfo_->codeCol = pos.second;
48     }
49 #ifdef UICAST_COMPONENT_SUPPORTED
50     do {
51         auto container = Container::Current();
52         CHECK_NULL_BREAK(container);
53         auto distributedUI = container->GetDistributedUI();
54         CHECK_NULL_BREAK(distributedUI);
55         distributedUI->AddNewNode(nodeId_);
56     } while (false);
57 #endif
58     instanceId_ = Container::CurrentId();
59     nodeStatus_ = ViewStackProcessor::GetInstance()->IsBuilderNode() ? NodeStatus::BUILDER_NODE_OFF_MAINTREE
60                                                                      : NodeStatus::NORMAL_NODE;
61 }
62 
~UINode()63 UINode::~UINode()
64 {
65 #ifdef UICAST_COMPONENT_SUPPORTED
66     do {
67         auto container = Container::Current();
68         CHECK_NULL_BREAK(container);
69         auto distributedUI = container->GetDistributedUI();
70         CHECK_NULL_BREAK(distributedUI);
71         if (hostPageId_ == distributedUI->GetCurrentPageId()) {
72             distributedUI->AddDeletedNode(nodeId_);
73         }
74     } while (false);
75 #endif
76 
77     if (!removeSilently_) {
78         ElementRegister::GetInstance()->RemoveItem(nodeId_);
79     } else {
80         ElementRegister::GetInstance()->RemoveItemSilently(nodeId_);
81     }
82     if (propInspectorId_.has_value()) {
83         ElementRegister::GetInstance()->RemoveFrameNodeByInspectorId(propInspectorId_.value_or(""), nodeId_);
84     }
85     if (!onMainTree_) {
86         return;
87     }
88     if (context_) {
89         context_->RemoveAttachedNode(this);
90     }
91     onMainTree_ = false;
92     if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
93         nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
94     }
95 }
96 
AttachContext(PipelineContext * context,bool recursive)97 void UINode::AttachContext(PipelineContext* context, bool recursive)
98 {
99     CHECK_NULL_VOID(context);
100     context_ = context;
101     context_->RegisterAttachedNode(this);
102     instanceId_ = context->GetInstanceId();
103     if (updateJSInstanceCallback_) {
104         updateJSInstanceCallback_(instanceId_);
105     }
106     if (recursive) {
107         for (auto& child : children_) {
108             child->AttachContext(context, recursive);
109         }
110     }
111 }
112 
DetachContext(bool recursive)113 void UINode::DetachContext(bool recursive)
114 {
115     CHECK_NULL_VOID(context_);
116     context_->DetachNode(Claim(this));
117     context_ = nullptr;
118     instanceId_ = INSTANCE_ID_UNDEFINED;
119     if (recursive) {
120         for (auto& child : children_) {
121             child->DetachContext(recursive);
122         }
123     }
124 }
125 
AddChild(const RefPtr<UINode> & child,int32_t slot,bool silently,bool addDefaultTransition,bool addModalUiextension)126 void UINode::AddChild(const RefPtr<UINode>& child, int32_t slot,
127     bool silently, bool addDefaultTransition, bool addModalUiextension)
128 {
129     CHECK_NULL_VOID(child);
130     if (!addModalUiextension && modalUiextensionCount_ > 0) {
131         LOGW("Current Node(id: %{public}d) is prohibited add child(tag %{public}s, id: %{public}d), "
132             "Current modalUiextension count is : %{public}d",
133             GetId(), child->GetTag().c_str(), child->GetId(), modalUiextensionCount_);
134         return;
135     }
136 
137     auto it = std::find(children_.begin(), children_.end(), child);
138     if (it != children_.end()) {
139         return;
140     }
141 
142     // remove from disappearing children
143     RemoveDisappearingChild(child);
144     it = children_.begin();
145     std::advance(it, slot);
146     DoAddChild(it, child, silently, addDefaultTransition);
147 }
148 
AddChildAfter(const RefPtr<UINode> & child,const RefPtr<UINode> & siblingNode)149 void UINode::AddChildAfter(const RefPtr<UINode>& child, const RefPtr<UINode>& siblingNode)
150 {
151     CHECK_NULL_VOID(child);
152     CHECK_NULL_VOID(siblingNode);
153     auto it = std::find(children_.begin(), children_.end(), child);
154     if (it != children_.end()) {
155         LOGW("Child node already exists. Existing child nodeId %{public}d, add %{public}s child nodeId nodeId "
156              "%{public}d",
157             (*it)->GetId(), child->GetTag().c_str(), child->GetId());
158         return;
159     }
160     // remove from disappearing children
161     RemoveDisappearingChild(child);
162     auto siblingNodeIter = std::find(children_.begin(), children_.end(), siblingNode);
163     if (siblingNodeIter != children_.end()) {
164         DoAddChild(++siblingNodeIter, child, false);
165         return;
166     }
167     it = children_.begin();
168     std::advance(it, -1);
169     DoAddChild(it, child, false);
170 }
171 
AddChildBefore(const RefPtr<UINode> & child,const RefPtr<UINode> & siblingNode)172 void UINode::AddChildBefore(const RefPtr<UINode>& child, const RefPtr<UINode>& siblingNode)
173 {
174     CHECK_NULL_VOID(child);
175     CHECK_NULL_VOID(siblingNode);
176     auto it = std::find(children_.begin(), children_.end(), child);
177     if (it != children_.end()) {
178         LOGW("Child node already exists. Existing child nodeId %{public}d, add %{public}s child nodeId nodeId "
179              "%{public}d",
180             (*it)->GetId(), child->GetTag().c_str(), child->GetId());
181         return;
182     }
183     // remove from disappearing children
184     RemoveDisappearingChild(child);
185     auto siblingNodeIter = std::find(children_.begin(), children_.end(), siblingNode);
186     if (siblingNodeIter != children_.end()) {
187         DoAddChild(siblingNodeIter, child, false);
188         return;
189     }
190     it = children_.begin();
191     std::advance(it, -1);
192     DoAddChild(it, child, false);
193 }
194 
TraversingCheck(RefPtr<UINode> node,bool withAbort)195 void UINode::TraversingCheck(RefPtr<UINode> node, bool withAbort)
196 {
197     if (isTraversing_) {
198         if (node) {
199             LOGF("Try to remove the child([%{public}s][%{public}d]) of node [%{public}s][%{public}d] when its children "
200                 "is traversing", node->GetTag().c_str(), node->GetId(), GetTag().c_str(), GetId());
201         } else {
202             LOGF("Try to remove all the children of node [%{public}s][%{public}d] when its children is traversing",
203                 GetTag().c_str(), GetId());
204         }
205         OHOS::Ace::LogBacktrace();
206 
207         if (withAbort) {
208             abort();
209         }
210     }
211 }
212 
RemoveChild(const RefPtr<UINode> & child,bool allowTransition)213 std::list<RefPtr<UINode>>::iterator UINode::RemoveChild(const RefPtr<UINode>& child, bool allowTransition)
214 {
215     CHECK_NULL_RETURN(child, children_.end());
216 
217     auto iter = std::find(children_.begin(), children_.end(), child);
218     if (iter == children_.end()) {
219         return children_.end();
220     }
221     // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to the
222     // disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved until the
223     // transition has finished. We can then perform the necessary cleanup after the transition is complete.
224     if ((*iter)->OnRemoveFromParent(allowTransition)) {
225         // OnRemoveFromParent returns true means the child can be removed from tree immediately.
226         RemoveDisappearingChild(child);
227     } else {
228         // else move child into disappearing children, skip syncing render tree
229         AddDisappearingChild(child, std::distance(children_.begin(), iter));
230     }
231     MarkNeedSyncRenderTree(true);
232     // Iter maybe lost in OnRemoveFromParent, needs reacquire.
233     iter = std::find(children_.begin(), children_.end(), child);
234     if (iter == children_.end()) {
235         LOGW("Iter is qeual to children end");
236         return children_.end();
237     }
238     TraversingCheck(*iter);
239     auto result = children_.erase(iter);
240     return result;
241 }
242 
RemoveChildAndReturnIndex(const RefPtr<UINode> & child)243 int32_t UINode::RemoveChildAndReturnIndex(const RefPtr<UINode>& child)
244 {
245     auto result = RemoveChild(child);
246     return std::distance(children_.begin(), result);
247 }
248 
RemoveChildAtIndex(int32_t index)249 void UINode::RemoveChildAtIndex(int32_t index)
250 {
251     auto children = GetChildren();
252     if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
253         return;
254     }
255     auto iter = children.begin();
256     std::advance(iter, index);
257     RemoveChild(*iter);
258 }
259 
GetChildAtIndex(int32_t index) const260 RefPtr<UINode> UINode::GetChildAtIndex(int32_t index) const
261 {
262     auto& children = GetChildren();
263     if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
264         return nullptr;
265     }
266     auto iter = children.begin();
267     std::advance(iter, index);
268     if (iter != children.end()) {
269         return *iter;
270     }
271     return nullptr;
272 }
273 
GetChildIndex(const RefPtr<UINode> & child) const274 int32_t UINode::GetChildIndex(const RefPtr<UINode>& child) const
275 {
276     int32_t index = 0;
277     for (const auto& iter : GetChildren()) {
278         if (iter == child) {
279             return index;
280         }
281         index++;
282     }
283     return -1;
284 }
285 
ReplaceChild(const RefPtr<UINode> & oldNode,const RefPtr<UINode> & newNode)286 void UINode::ReplaceChild(const RefPtr<UINode>& oldNode, const RefPtr<UINode>& newNode)
287 {
288     if (!oldNode) {
289         if (newNode) {
290             AddChild(newNode);
291         }
292         return;
293     }
294 
295     auto iter = RemoveChild(oldNode);
296     DoAddChild(iter, newNode, false, false);
297 }
298 
Clean(bool cleanDirectly,bool allowTransition,int32_t branchId)299 void UINode::Clean(bool cleanDirectly, bool allowTransition, int32_t branchId)
300 {
301     bool needSyncRenderTree = false;
302     int32_t index = 0;
303 
304     auto children = GetChildren();
305     for (const auto& child : children) {
306         // traverse down the child subtree to mark removing and find needs to hold subtree, if found add it to pending
307         if (!cleanDirectly && child->MarkRemoving()) {
308             ElementRegister::GetInstance()->AddPendingRemoveNode(child);
309         }
310         // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to
311         // the disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved
312         // until the transition has finished. We can then perform the necessary cleanup after the transition is
313         // complete.
314         if (child->OnRemoveFromParent(allowTransition)) {
315             // OnRemoveFromParent returns true means the child can be removed from tree immediately.
316             RemoveDisappearingChild(child);
317             needSyncRenderTree = true;
318         } else {
319             // else move child into disappearing children, skip syncing render tree
320             AddDisappearingChild(child, index, branchId);
321         }
322         ++index;
323     }
324     if (tag_ != V2::JS_IF_ELSE_ETS_TAG) {
325         children_.clear();
326     }
327     MarkNeedSyncRenderTree(true);
328 }
329 
MountToParent(const RefPtr<UINode> & parent,int32_t slot,bool silently,bool addDefaultTransition,bool addModalUiextension)330 void UINode::MountToParent(const RefPtr<UINode>& parent,
331     int32_t slot, bool silently, bool addDefaultTransition, bool addModalUiextension)
332 {
333     CHECK_NULL_VOID(parent);
334     parent->AddChild(AceType::Claim(this), slot, silently, addDefaultTransition, addModalUiextension);
335     if (parent->IsInDestroying()) {
336         parent->SetChildrenInDestroying();
337     }
338     if (parent->GetPageId() != 0) {
339         SetHostPageId(parent->GetPageId());
340     }
341     AfterMountToParent();
342 }
343 
UpdateConfigurationUpdate(const ConfigurationChange & configurationChange)344 void UINode::UpdateConfigurationUpdate(const ConfigurationChange& configurationChange)
345 {
346     OnConfigurationUpdate(configurationChange);
347     if (needCallChildrenUpdate_) {
348         auto children = GetChildren();
349         for (const auto& child : children) {
350             if (!child) {
351                 continue;
352             }
353             child->UpdateConfigurationUpdate(configurationChange);
354         }
355     }
356 }
357 
OnRemoveFromParent(bool allowTransition)358 bool UINode::OnRemoveFromParent(bool allowTransition)
359 {
360     // The recursive flag will used by RenderContext, if recursive flag is false,
361     // it may trigger transition
362     DetachFromMainTree(!allowTransition);
363     if (allowTransition && !RemoveImmediately()) {
364         return false;
365     }
366     ResetParent();
367     return true;
368 }
369 
ResetParent()370 void UINode::ResetParent()
371 {
372     parent_.Reset();
373     depth_ = -1;
374 }
375 
376 namespace {
operator <<(std::ostream & ss,const RefPtr<UINode> & node)377 std::ostream& operator<<(std::ostream& ss, const RefPtr<UINode>& node)
378 {
379     return ss << node->GetId() << "(" << node->GetTag() << "," << node->GetDepth()
380         << "," << node->GetChildren().size() << ")";
381 }
382 
ToString(const RefPtr<UINode> & node)383 std::string ToString(const RefPtr<UINode>& node)
384 {
385     std::stringstream ss;
386     ss << node;
387     for (auto parent = node->GetParent(); parent; parent = parent->GetParent()) {
388         ss << "->" << parent;
389     }
390     return ss.str();
391 }
392 
LoopDetected(const RefPtr<UINode> & child,const RefPtr<UINode> & current)393 void LoopDetected(const RefPtr<UINode>& child, const RefPtr<UINode>& current)
394 {
395     auto childNode = ToString(child);
396     auto currentNode = ToString(current);
397 
398     constexpr size_t totalLengthLimit = 900; // hilog oneline length limit is 1024
399     constexpr size_t childLengthLimit = 100;
400     static_assert(totalLengthLimit > childLengthLimit, "totalLengthLimit too small");
401     constexpr size_t currentLengthLimit = totalLengthLimit - childLengthLimit;
402 
403     LOGF("Detected loop: child[%{public}.*s] vs current[%{public}.*s]",
404         (int)childLengthLimit, childNode.c_str(), (int)currentLengthLimit, currentNode.c_str());
405 
406     // log full childNode info in case of hilog length limit reached
407     if (childNode.length() > childLengthLimit) {
408         auto s = childNode.c_str();
409         for (size_t i = 0; i < childNode.length(); i += totalLengthLimit) {
410             LOGI("child.%{public}zu:[%{public}.*s]", i, (int)totalLengthLimit, s + i);
411         }
412     }
413 
414     // log full currentNode info in case of hilog length limit reached
415     if (currentNode.length() > currentLengthLimit) {
416         auto s = currentNode.c_str();
417         for (size_t i = 0; i < currentNode.length(); i += totalLengthLimit) {
418             LOGI("current.%{public}zu:[%{public}.*s]", i, (int)totalLengthLimit, s + i);
419         }
420     }
421 
422     if (SystemProperties::GetLayoutDetectEnabled()) {
423         abort();
424     } else {
425         LogBacktrace();
426     }
427 }
428 
DetectLoop(const RefPtr<UINode> & child,const RefPtr<UINode> & current)429 bool DetectLoop(const RefPtr<UINode>& child, const RefPtr<UINode>& current)
430 {
431     if ((child->GetDepth() > 0 && child->GetDepth() < INT32_MAX) || child == current) {
432         for (auto parent = current; parent; parent = parent->GetParent()) {
433             if (parent == child) {
434                 LoopDetected(child, current);
435                 return true;
436             }
437         }
438     }
439     return false;
440 }
441 }
442 
DoAddChild(std::list<RefPtr<UINode>>::iterator & it,const RefPtr<UINode> & child,bool silently,bool addDefaultTransition)443 void UINode::DoAddChild(
444     std::list<RefPtr<UINode>>::iterator& it, const RefPtr<UINode>& child, bool silently, bool addDefaultTransition)
445 {
446     if (DetectLoop(child, Claim(this))) {
447         return;
448     }
449     children_.insert(it, child);
450 
451     if (IsAccessibilityVirtualNode()) {
452         auto parentVirtualNode = GetVirtualNodeParent().Upgrade();
453         if (parentVirtualNode) {
454             child->SetAccessibilityNodeVirtual();
455             child->SetAccessibilityVirtualNodeParent(parentVirtualNode);
456         }
457     }
458 
459     child->SetParent(Claim(this));
460     child->SetDepth(GetDepth() + 1);
461     if (nodeStatus_ != NodeStatus::NORMAL_NODE) {
462         child->UpdateNodeStatus(nodeStatus_);
463     }
464 
465     if (!silently && onMainTree_) {
466         child->AttachToMainTree(!addDefaultTransition, context_);
467     }
468     MarkNeedSyncRenderTree(true);
469 }
470 
GetBestBreakPoint(RefPtr<UINode> & breakPointChild,RefPtr<UINode> & breakPointParent)471 void UINode::GetBestBreakPoint(RefPtr<UINode>& breakPointChild, RefPtr<UINode>& breakPointParent)
472 {
473     while (breakPointParent && !breakPointChild->IsDisappearing()) {
474         // recursively looking up the node tree, until we reach the breaking point (IsDisappearing() == true).
475         // Because when trigger transition, only the breakPoint will be marked as disappearing and
476         // moved to disappearingChildren.
477         breakPointChild = breakPointParent;
478         breakPointParent = breakPointParent->GetParent();
479     }
480     RefPtr<UINode> betterChild = breakPointChild;
481     RefPtr<UINode> betterParent = breakPointParent;
482     // when current breakPointParent is UINode, looking up the node tree to see whether there is a better breakPoint.
483     while (betterParent && !InstanceOf<FrameNode>(betterParent)) {
484         if (betterChild->IsDisappearing()) {
485             if (!betterChild->RemoveImmediately()) {
486                 break;
487             }
488             breakPointChild = betterChild;
489             breakPointParent = betterParent;
490         }
491         betterChild = betterParent;
492         betterParent = betterParent->GetParent();
493     }
494 }
495 
RemoveFromParentCleanly(const RefPtr<UINode> & child,const RefPtr<UINode> & parent)496 void UINode::RemoveFromParentCleanly(const RefPtr<UINode>& child, const RefPtr<UINode>& parent)
497 {
498     if (!parent->RemoveDisappearingChild(child)) {
499         auto& children = parent->ModifyChildren();
500         auto iter = std::find(children.begin(), children.end(), child);
501         if (iter != children.end()) {
502             parent->TraversingCheck(*iter);
503             children.erase(iter);
504         }
505     }
506     auto frameChild = DynamicCast<FrameNode>(child);
507     if (frameChild->GetRenderContext()->HasTransitionOutAnimation()) {
508         // delete the real breakPoint.
509         RefPtr<UINode> breakPointChild = child;
510         RefPtr<UINode> breakPointParent = parent;
511         GetBestBreakPoint(breakPointChild, breakPointParent);
512         if (breakPointParent && breakPointChild->RemoveImmediately()) {
513             // Result of RemoveImmediately of the breakPointChild is true and
514             // result of RemoveImmediately of the child is false,
515             // so breakPointChild must be different from child in this branch.
516             breakPointParent->RemoveDisappearingChild(breakPointChild);
517             breakPointParent->MarkNeedSyncRenderTree();
518         }
519     }
520 }
521 
GetParentFrameNode() const522 RefPtr<FrameNode> UINode::GetParentFrameNode() const
523 {
524     auto parent = GetParent();
525     while (parent) {
526         auto parentFrame = AceType::DynamicCast<FrameNode>(parent);
527         if (parentFrame) {
528             return parentFrame;
529         }
530         parent = parent->GetParent();
531     }
532     return nullptr;
533 }
534 
GetParentCustomNode() const535 RefPtr<CustomNode> UINode::GetParentCustomNode() const
536 {
537     auto parent = GetParent();
538     while (parent) {
539         auto customNode = AceType::DynamicCast<CustomNode>(parent);
540         if (customNode) {
541             return customNode;
542         }
543         parent = parent->GetParent();
544     }
545     return nullptr;
546 }
547 
GetFocusParent() const548 RefPtr<FrameNode> UINode::GetFocusParent() const
549 {
550     auto parentUi = GetParent();
551     while (parentUi) {
552         auto parentFrame = AceType::DynamicCast<FrameNode>(parentUi);
553         if (!parentFrame) {
554             parentUi = parentUi->GetParent();
555             continue;
556         }
557         auto type = parentFrame->GetFocusType();
558         if (type == FocusType::SCOPE) {
559             return parentFrame;
560         }
561         if (type == FocusType::NODE) {
562             return nullptr;
563         }
564         parentUi = parentUi->GetParent();
565     }
566     return nullptr;
567 }
568 
GetFirstFocusHubChild() const569 RefPtr<FocusHub> UINode::GetFirstFocusHubChild() const
570 {
571     const auto* frameNode = AceType::DynamicCast<FrameNode>(this);
572     if (frameNode) {
573         auto focusHub = frameNode->GetFocusHub();
574         if (focusHub && focusHub->GetFocusType() != FocusType::DISABLE) {
575             return focusHub;
576         }
577     }
578     for (const auto& child : GetChildren()) {
579         auto focusHub = child->GetFirstFocusHubChild();
580         if (focusHub) {
581             return focusHub;
582         }
583     }
584     return nullptr;
585 }
586 
GetFocusChildren(std::list<RefPtr<FrameNode>> & children) const587 void UINode::GetFocusChildren(std::list<RefPtr<FrameNode>>& children) const
588 {
589     auto uiChildren = GetChildren();
590     for (const auto& uiChild : uiChildren) {
591         auto frameChild = AceType::DynamicCast<FrameNode>(uiChild);
592         if (frameChild && frameChild->GetFocusType() != FocusType::DISABLE) {
593             children.emplace_back(frameChild);
594         } else {
595             uiChild->GetFocusChildren(children);
596         }
597     }
598 }
599 
GetCurrentChildrenFocusHub(std::list<RefPtr<FocusHub>> & focusNodes)600 void UINode::GetCurrentChildrenFocusHub(std::list<RefPtr<FocusHub>>& focusNodes)
601 {
602     for (const auto& uiChild : children_) {
603         auto frameChild = AceType::DynamicCast<FrameNode>(uiChild.GetRawPtr());
604         if (frameChild && frameChild->GetFocusType() != FocusType::DISABLE) {
605             const auto focusHub = frameChild->GetFocusHub();
606             if (focusHub) {
607                 focusNodes.emplace_back(focusHub);
608             }
609         } else {
610             uiChild->GetCurrentChildrenFocusHub(focusNodes);
611         }
612     }
613 }
614 
AttachToMainTree(bool recursive,PipelineContext * context)615 void UINode::AttachToMainTree(bool recursive, PipelineContext* context)
616 {
617     if (onMainTree_) {
618         return;
619     }
620     // the context should not be nullptr.
621     AttachContext(context, false);
622     onMainTree_ = true;
623     if (nodeStatus_ == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
624         nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE;
625     }
626     isRemoving_ = false;
627     OnAttachToMainTree(recursive);
628     // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
629     bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
630     for (const auto& child : GetChildren()) {
631         child->AttachToMainTree(isRecursive, context);
632     }
633     if (context && context->IsOpenInvisibleFreeze()) {
634         auto parent = GetParent();
635         // if it does not has parent, reset the flag.
636         SetFreeze(parent ? parent->isFreeze_ : false);
637     }
638 }
639 
AttachToMainTree(bool recursive)640 [[deprecated]] void UINode::AttachToMainTree(bool recursive)
641 {
642     if (onMainTree_) {
643         return;
644     }
645     onMainTree_ = true;
646     if (nodeStatus_ == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
647         nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE;
648     }
649     isRemoving_ = false;
650     OnAttachToMainTree(recursive);
651     // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
652     bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
653     for (const auto& child : GetChildren()) {
654         child->AttachToMainTree(isRecursive);
655     }
656 }
657 
DetachFromMainTree(bool recursive)658 void UINode::DetachFromMainTree(bool recursive)
659 {
660     if (!onMainTree_) {
661         return;
662     }
663     onMainTree_ = false;
664     if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
665         nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
666     }
667     isRemoving_ = true;
668     auto context = context_;
669     DetachContext(false);
670     OnDetachFromMainTree(recursive, context);
671     // if recursive = false, recursively call DetachFromMainTree(false), until we reach the first FrameNode.
672     bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
673     isTraversing_ = true;
674     std::list<RefPtr<UINode>> children = GetChildren();
675     for (const auto& child : children) {
676         child->DetachFromMainTree(isRecursive);
677     }
678     isTraversing_ = false;
679 }
680 
SetFreeze(bool isFreeze)681 void UINode::SetFreeze(bool isFreeze)
682 {
683     auto context = GetContext();
684     CHECK_NULL_VOID(context);
685     auto isOpenInvisibleFreeze = context->IsOpenInvisibleFreeze();
686     if (isOpenInvisibleFreeze && isFreeze_ != isFreeze) {
687         isFreeze_ = isFreeze;
688         OnFreezeStateChange();
689         UpdateChildrenFreezeState(isFreeze_);
690     }
691 }
692 
UpdateChildrenFreezeState(bool isFreeze)693 void UINode::UpdateChildrenFreezeState(bool isFreeze)
694 {
695     const auto& children = GetChildren(true);
696     for (const auto& child : children) {
697         if (child) {
698             child->SetFreeze(isFreeze);
699         }
700     }
701 }
702 
FireCustomDisappear()703 void UINode::FireCustomDisappear()
704 {
705     std::list<RefPtr<UINode>> children = GetChildren();
706     for (const auto& child : children) {
707         child->FireCustomDisappear();
708     }
709 }
710 
ProcessOffscreenTask(bool recursive)711 void UINode::ProcessOffscreenTask(bool recursive)
712 {
713     if (useOffscreenProcess_) {
714         return;
715     }
716     useOffscreenProcess_ = true;
717     OnOffscreenProcess(recursive);
718     // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
719     bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
720     for (const auto& child : GetChildren()) {
721         child->ProcessOffscreenTask(isRecursive);
722     }
723 }
724 
MovePosition(int32_t slot)725 void UINode::MovePosition(int32_t slot)
726 {
727     auto parentNode = parent_.Upgrade();
728     CHECK_NULL_VOID(parentNode);
729 
730     auto self = AceType::Claim(this);
731     auto& children = parentNode->children_;
732     auto it = children.end();
733     if (slot >= 0 && static_cast<size_t>(slot) < children.size()) {
734         it = children.begin();
735         std::advance(it, slot);
736         if ((it != children.end()) && (*it == this)) {
737             // Already at the right place
738             return;
739         }
740 
741         auto itSelf = std::find(it, children.end(), self);
742         if (itSelf != children.end()) {
743             parentNode->TraversingCheck(*itSelf);
744             children.erase(itSelf);
745         } else {
746             parentNode->TraversingCheck(self);
747             children.remove(self);
748             ++it;
749         }
750     } else {
751         parentNode->TraversingCheck(self);
752         children.remove(self);
753     }
754     children.insert(it, self);
755     parentNode->MarkNeedSyncRenderTree(true);
756 }
757 
UpdateLayoutPropertyFlag()758 void UINode::UpdateLayoutPropertyFlag()
759 {
760     for (const auto& child : GetChildren()) {
761         child->UpdateLayoutPropertyFlag();
762     }
763 }
764 
AdjustParentLayoutFlag(PropertyChangeFlag & flag)765 void UINode::AdjustParentLayoutFlag(PropertyChangeFlag& flag)
766 {
767     for (const auto& child : GetChildren()) {
768         child->AdjustParentLayoutFlag(flag);
769     }
770 }
771 
MarkDirtyNode(PropertyChangeFlag extraFlag)772 void UINode::MarkDirtyNode(PropertyChangeFlag extraFlag)
773 {
774     for (const auto& child : GetChildren()) {
775         child->MarkDirtyNode(extraFlag);
776     }
777 }
778 
MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)779 void UINode::MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)
780 {
781     auto parent = parent_.Upgrade();
782     if (parent) {
783         parent->MarkNeedFrameFlushDirty(extraFlag);
784     }
785 }
786 
MarkNeedSyncRenderTree(bool needRebuild)787 void UINode::MarkNeedSyncRenderTree(bool needRebuild)
788 {
789     auto parent = parent_.Upgrade();
790     if (parent) {
791         parent->MarkNeedSyncRenderTree(needRebuild);
792     }
793 }
794 
RebuildRenderContextTree()795 void UINode::RebuildRenderContextTree()
796 {
797     auto parent = parent_.Upgrade();
798     if (parent) {
799         parent->RebuildRenderContextTree();
800     }
801 }
OnDetachFromMainTree(bool,PipelineContext *)802 void UINode::OnDetachFromMainTree(bool, PipelineContext*) {}
803 
OnAttachToMainTree(bool)804 void UINode::OnAttachToMainTree(bool)
805 {
806     useOffscreenProcess_ = false;
807 }
808 
UpdateGeometryTransition()809 void UINode::UpdateGeometryTransition()
810 {
811     auto children = GetChildren();
812     for (const auto& child: children) {
813         child->UpdateGeometryTransition();
814     }
815 }
816 
IsAutoFillContainerNode()817 bool UINode::IsAutoFillContainerNode()
818 {
819     return tag_ == V2::PAGE_ETS_TAG || tag_ == V2::NAVDESTINATION_VIEW_ETS_TAG || tag_ == V2::DIALOG_ETS_TAG
820         || tag_ == V2::SHEET_PAGE_TAG || tag_ == V2::MODAL_PAGE_TAG;
821 }
822 
DumpViewDataPageNodes(RefPtr<ViewDataWrap> viewDataWrap,bool skipSubAutoFillContainer,bool needsRecordData)823 void UINode::DumpViewDataPageNodes(
824     RefPtr<ViewDataWrap> viewDataWrap, bool skipSubAutoFillContainer, bool needsRecordData)
825 {
826     auto frameNode = AceType::DynamicCast<FrameNode>(this);
827     if (frameNode && !frameNode->IsVisible()) {
828         auto pattern = frameNode->GetPattern();
829         if (pattern && !pattern->TriggerAutoSaveWhenInvisible()) {
830             return;
831         }
832     }
833     DumpViewDataPageNode(viewDataWrap, needsRecordData);
834     for (const auto& item : GetChildren()) {
835         if (!item) {
836             continue;
837         }
838         if (skipSubAutoFillContainer && item->IsAutoFillContainerNode()) {
839             continue;
840         }
841         item->DumpViewDataPageNodes(viewDataWrap, skipSubAutoFillContainer, needsRecordData);
842     }
843 }
844 
NeedRequestAutoSave()845 bool UINode::NeedRequestAutoSave()
846 {
847     auto frameNode = AceType::DynamicCast<FrameNode>(this);
848     if (frameNode && !frameNode->IsVisible()) {
849         auto pattern = frameNode->GetPattern();
850         if (pattern && !pattern->TriggerAutoSaveWhenInvisible()) {
851             return false;
852         }
853     }
854     if (CheckAutoSave()) {
855         return true;
856     }
857     for (const auto& item : GetChildren()) {
858         if (item->NeedRequestAutoSave()) {
859             return true;
860         }
861     }
862     return false;
863 }
864 
DumpTree(int32_t depth)865 void UINode::DumpTree(int32_t depth)
866 {
867     if (DumpLog::GetInstance().GetDumpFile()) {
868         DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
869         DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(GetDepth())));
870         DumpLog::GetInstance().AddDesc("AccessibilityId: " + std::to_string(accessibilityId_));
871         if (IsDisappearing()) {
872             DumpLog::GetInstance().AddDesc(std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
873         }
874         DumpInfo();
875         DumpLog::GetInstance().Append(depth, tag_, static_cast<int32_t>(GetChildren().size()));
876     }
877     for (const auto& item : GetChildren()) {
878         item->DumpTree(depth + 1);
879     }
880     for (const auto& [item, index, branch] : disappearingChildren_) {
881         item->DumpTree(depth + 1);
882     }
883     auto frameNode = AceType::DynamicCast<FrameNode>(this);
884     if (frameNode && frameNode->GetOverlayNode()) {
885         frameNode->GetOverlayNode()->DumpTree(depth + 1);
886     }
887 }
888 
DumpSimplifyTree(int32_t depth,std::unique_ptr<JsonValue> & current)889 void UINode::DumpSimplifyTree(int32_t depth, std::unique_ptr<JsonValue>& current)
890 {
891     current->Put("ID", nodeId_);
892     current->Put("Type", tag_.c_str());
893     auto nodeChildren = GetChildren();
894     DumpSimplifyInfo(current);
895     bool hasChildren = !nodeChildren.empty() || !disappearingChildren_.empty();
896     if (hasChildren) {
897         current->Put("ChildrenSize", static_cast<int32_t>(nodeChildren.size()));
898         auto array = JsonUtil::CreateArray();
899         if (!nodeChildren.empty()) {
900             for (const auto& item : nodeChildren) {
901                 auto child = JsonUtil::Create();
902                 item->DumpSimplifyTree(depth + 1, child);
903                 array->PutRef(std::move(child));
904             }
905         }
906         if (!disappearingChildren_.empty()) {
907             for (const auto& [item, index, branch] : disappearingChildren_) {
908                 auto child = JsonUtil::Create();
909                 item->DumpSimplifyTree(depth + 1, child);
910                 array->PutRef(std::move(child));
911             }
912         }
913         current->PutRef("Children", std::move(array));
914     }
915     auto frameNode = AceType::DynamicCast<FrameNode>(this);
916     if (frameNode && frameNode->GetOverlayNode()) {
917         auto overlay = JsonUtil::Create();
918         frameNode->GetOverlayNode()->DumpSimplifyTree(depth + 1, overlay);
919         current->PutRef("Overlay", std::move(overlay));
920     }
921 }
922 
DumpTreeById(int32_t depth,const std::string & id)923 bool UINode::DumpTreeById(int32_t depth, const std::string& id)
924 {
925     if (DumpLog::GetInstance().GetDumpFile() &&
926         (id == propInspectorId_.value_or("") || id == std::to_string(nodeId_))) {
927         DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
928         DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(GetDepth())));
929         DumpLog::GetInstance().AddDesc(std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
930         DumpAdvanceInfo();
931         DumpLog::GetInstance().Print(depth, tag_, static_cast<int32_t>(GetChildren().size()));
932         return true;
933     }
934     for (const auto& item : GetChildren()) {
935         if (item->DumpTreeById(depth + 1, id)) {
936             return true;
937         }
938     }
939     for (const auto& [item, index, branch] : disappearingChildren_) {
940         if (item->DumpTreeById(depth + 1, id)) {
941             return true;
942         }
943     }
944     return false;
945 }
946 
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)947 void UINode::AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
948 {
949     for (const auto& child : children_) {
950         if (!child->IsInDestroying()) {
951             child->AdjustLayoutWrapperTree(parent, forceMeasure, forceLayout);
952         }
953     }
954 }
955 
GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>> & visibleList)956 void UINode::GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>>& visibleList)
957 {
958     for (const auto& child : GetChildren()) {
959         child->OnGenerateOneDepthVisibleFrame(visibleList);
960     }
961 }
962 
GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)963 void UINode::GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
964 {
965     if (disappearingChildren_.empty()) {
966         // normal child
967         for (const auto& child : GetChildren()) {
968             child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
969         }
970         return;
971     }
972     // generate the merged list of children_ and disappearingChildren_
973     auto allChildren = GetChildren();
974     for (auto iter = disappearingChildren_.rbegin(); iter != disappearingChildren_.rend(); ++iter) {
975         auto& [disappearingChild, index, _] = *iter;
976         if (index >= allChildren.size()) {
977             allChildren.emplace_back(disappearingChild);
978         } else {
979             auto insertIter = allChildren.begin();
980             std::advance(insertIter, index);
981             allChildren.insert(insertIter, disappearingChild);
982         }
983     }
984     for (const auto& child : allChildren) {
985         child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
986     }
987 }
988 
GenerateOneDepthVisibleFrameWithOffset(std::list<RefPtr<FrameNode>> & visibleList,OffsetF & offset)989 void UINode::GenerateOneDepthVisibleFrameWithOffset(
990     std::list<RefPtr<FrameNode>>& visibleList, OffsetF& offset)
991 {
992     if (disappearingChildren_.empty()) {
993         // normal child
994         for (const auto& child : GetChildren()) {
995             child->OnGenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
996         }
997         return;
998     }
999     // generate the merged list of children_ and disappearingChildren_
1000     auto allChildren = GetChildren();
1001     for (auto iter = disappearingChildren_.rbegin(); iter != disappearingChildren_.rend(); ++iter) {
1002         auto& [disappearingChild, index, _] = *iter;
1003         if (index >= allChildren.size()) {
1004             allChildren.emplace_back(disappearingChild);
1005         } else {
1006             auto insertIter = allChildren.begin();
1007             std::advance(insertIter, index);
1008             allChildren.insert(insertIter, disappearingChild);
1009         }
1010     }
1011     for (const auto& child : allChildren) {
1012         child->OnGenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
1013     }
1014 }
1015 
GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>> & visibleList)1016 void UINode::GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>>& visibleList)
1017 {
1018     for (const auto& child : GetChildren()) {
1019         child->OnGenerateOneDepthAllFrame(visibleList);
1020     }
1021 }
1022 
GetContext() const1023 PipelineContext* UINode::GetContext() const
1024 {
1025     PipelineContext* context = nullptr;
1026     if (context_) {
1027         context = context_;
1028     } else {
1029         if (externalData_) {
1030             context = PipelineContext::GetCurrentContextPtrSafelyWithCheck();
1031         } else {
1032             context = PipelineContext::GetCurrentContextPtrSafely();
1033         }
1034     }
1035     return context;
1036 }
1037 
GetAttachedContext() const1038 PipelineContext* UINode::GetAttachedContext() const
1039 {
1040     return context_;
1041 }
1042 
GetContextWithCheck()1043 PipelineContext* UINode::GetContextWithCheck()
1044 {
1045     if (context_) {
1046         return context_;
1047     }
1048     return PipelineContext::GetCurrentContextPtrSafelyWithCheck();
1049 }
1050 
GetContextRefPtr() const1051 RefPtr<PipelineContext> UINode::GetContextRefPtr() const
1052 {
1053     auto* context = GetContext();
1054     return Claim(context);
1055 }
1056 
TouchTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,TouchTestResult & result,int32_t touchId,ResponseLinkResult & responseLinkResult,bool isDispatch)1057 HitTestResult UINode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1058     const PointF& parentRevertPoint, TouchRestrict& touchRestrict, TouchTestResult& result, int32_t touchId,
1059     ResponseLinkResult& responseLinkResult, bool isDispatch)
1060 {
1061     auto children = GetChildren();
1062     HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1063     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1064         auto& child = *iter;
1065         auto hitResult = child->TouchTest(
1066             globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, result, touchId, responseLinkResult);
1067         if (hitResult == HitTestResult::STOP_BUBBLING) {
1068             return HitTestResult::STOP_BUBBLING;
1069         }
1070         if (hitResult == HitTestResult::BUBBLING) {
1071             hitTestResult = HitTestResult::BUBBLING;
1072         }
1073     }
1074     return hitTestResult;
1075 }
1076 
MouseTest(const PointF & globalPoint,const PointF & parentLocalPoint,MouseTestResult & onMouseResult,MouseTestResult & onHoverResult,RefPtr<FrameNode> & hoverNode)1077 HitTestResult UINode::MouseTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1078     MouseTestResult& onMouseResult, MouseTestResult& onHoverResult, RefPtr<FrameNode>& hoverNode)
1079 {
1080     auto children = GetChildren();
1081     HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1082     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1083         auto& child = *iter;
1084         auto hitResult = child->MouseTest(globalPoint, parentLocalPoint, onMouseResult, onHoverResult, hoverNode);
1085         if (hitResult == HitTestResult::STOP_BUBBLING) {
1086             return HitTestResult::STOP_BUBBLING;
1087         }
1088         if (hitResult == HitTestResult::BUBBLING) {
1089             hitTestResult = HitTestResult::BUBBLING;
1090         }
1091     }
1092     return hitTestResult;
1093 }
1094 
AxisTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,AxisTestResult & onAxisResult)1095 HitTestResult UINode::AxisTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1096     const PointF& parentRevertPoint, TouchRestrict& touchRestrict, AxisTestResult& onAxisResult)
1097 {
1098     auto children = GetChildren();
1099     HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
1100     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1101         auto& child = *iter;
1102         auto hitResult = child->AxisTest(globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, onAxisResult);
1103         if (hitResult == HitTestResult::STOP_BUBBLING) {
1104             return HitTestResult::STOP_BUBBLING;
1105         }
1106         if (hitResult == HitTestResult::BUBBLING) {
1107             hitTestResult = HitTestResult::BUBBLING;
1108         }
1109     }
1110     return hitTestResult;
1111 }
1112 
1113 
FrameCount() const1114 int32_t UINode::FrameCount() const
1115 {
1116     return TotalChildCount();
1117 }
1118 
TotalChildCount() const1119 int32_t UINode::TotalChildCount() const
1120 {
1121     int32_t count = 0;
1122     for (const auto& child : GetChildren()) {
1123         count += child->FrameCount();
1124     }
1125     return count;
1126 }
1127 
CurrentFrameCount() const1128 int32_t UINode::CurrentFrameCount() const
1129 {
1130     int32_t count = 0;
1131     for (const auto& child : GetChildren()) {
1132         count += child->CurrentFrameCount();
1133     }
1134     return count;
1135 }
1136 
GetChildIndexById(int32_t id)1137 int32_t UINode::GetChildIndexById(int32_t id)
1138 {
1139     int32_t pos = 0;
1140     auto children = GetChildren();
1141     auto iter = children.begin();
1142     while (iter != children.end()) {
1143         if (id == (*iter)->GetId()) {
1144             return pos;
1145         }
1146         pos++;
1147         iter++;
1148     }
1149     return -1;
1150 }
1151 
CreateLayoutWrapper(bool forceMeasure,bool forceLayout)1152 RefPtr<LayoutWrapperNode> UINode::CreateLayoutWrapper(bool forceMeasure, bool forceLayout)
1153 {
1154     if (GetChildren().empty()) {
1155         return nullptr;
1156     }
1157 
1158     auto child = GetChildren().front();
1159     while (!InstanceOf<FrameNode>(child)) {
1160         auto children = child->GetChildren();
1161         if (children.empty()) {
1162             return nullptr;
1163         }
1164 
1165         child = children.front();
1166     }
1167 
1168     auto frameChild = DynamicCast<FrameNode>(child);
1169     return frameChild ? frameChild->CreateLayoutWrapper(forceMeasure, forceLayout) : nullptr;
1170 }
1171 
RenderCustomChild(int64_t deadline)1172 bool UINode::RenderCustomChild(int64_t deadline)
1173 {
1174     for (const auto& child : GetChildren()) {
1175         if (child && !child->RenderCustomChild(deadline)) {
1176             return false;
1177         }
1178     }
1179     return true;
1180 }
1181 
Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)1182 void UINode::Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)
1183 {
1184     ACE_LAYOUT_TRACE_BEGIN("Build[%s][self:%d][parent:%d][key:%s]", GetTag().c_str(), GetId(),
1185         GetParent() ? GetParent()->GetId() : 0, GetInspectorIdValue("").c_str());
1186     std::vector<RefPtr<UINode>> children;
1187     children.reserve(GetChildren().size());
1188     for (const auto& child : GetChildren()) {
1189         children.push_back(child);
1190     }
1191     for (const auto& child : children) {
1192         if (InstanceOf<CustomNode>(child)) {
1193             auto custom = DynamicCast<CustomNode>(child);
1194             if (custom->HasExtraInfo()) {
1195                 if (!extraInfos) {
1196                     extraInfos = std::make_shared<std::list<ExtraInfo>>();
1197                 }
1198                 extraInfos->emplace_front(custom->GetExtraInfo());
1199                 custom->Build(extraInfos);
1200                 extraInfos->pop_front();
1201             } else {
1202                 custom->Build(extraInfos);
1203             }
1204         } else {
1205             child->Build(extraInfos);
1206         }
1207     }
1208     ACE_LAYOUT_TRACE_END()
1209 }
1210 
CreateExportTextureInfoIfNeeded()1211 void UINode::CreateExportTextureInfoIfNeeded()
1212 {
1213     if (!exportTextureInfo_) {
1214         exportTextureInfo_ = MakeRefPtr<ExportTextureInfo>();
1215     }
1216 }
1217 
IsNeedExportTexture() const1218 bool UINode::IsNeedExportTexture() const
1219 {
1220     return exportTextureInfo_ && exportTextureInfo_->GetCurrentRenderType() == NodeRenderType::RENDER_TYPE_TEXTURE;
1221 }
1222 
SetActive(bool active,bool needRebuildRenderContext)1223 void UINode::SetActive(bool active, bool needRebuildRenderContext)
1224 {
1225     for (const auto& child : GetChildren()) {
1226         child->SetActive(active, needRebuildRenderContext);
1227     }
1228 }
1229 
SetJSViewActive(bool active,bool isLazyForEachNode)1230 void UINode::SetJSViewActive(bool active, bool isLazyForEachNode)
1231 {
1232     for (const auto& child : GetChildren()) {
1233         auto customNode = AceType::DynamicCast<CustomNode>(child);
1234         // do not need to recursive here, stateMgmt will recursive all children when set active
1235         if (customNode && customNode->GetIsV2() && isLazyForEachNode) {
1236             return;
1237         }
1238         if (customNode) {
1239             customNode->SetJSViewActive(active);
1240             continue;
1241         }
1242         child->SetJSViewActive(active);
1243     }
1244 }
1245 
TryVisibleChangeOnDescendant(VisibleType preVisibility,VisibleType currentVisibility)1246 void UINode::TryVisibleChangeOnDescendant(VisibleType preVisibility, VisibleType currentVisibility)
1247 {
1248     UpdateChildrenVisible(preVisibility, currentVisibility);
1249 }
1250 
UpdateChildrenVisible(VisibleType preVisibility,VisibleType currentVisibility) const1251 void UINode::UpdateChildrenVisible(VisibleType preVisibility, VisibleType currentVisibility) const
1252 {
1253     for (const auto& child : GetChildren()) {
1254         child->TryVisibleChangeOnDescendant(preVisibility, currentVisibility);
1255     }
1256 }
1257 
OnRecycle()1258 void UINode::OnRecycle()
1259 {
1260     for (const auto& child : GetChildren()) {
1261         child->OnRecycle();
1262     }
1263 }
1264 
OnReuse()1265 void UINode::OnReuse()
1266 {
1267     for (const auto& child : GetChildren()) {
1268         child->OnReuse();
1269     }
1270 }
1271 
GetChildFlatIndex(int32_t id)1272 std::pair<bool, int32_t> UINode::GetChildFlatIndex(int32_t id)
1273 {
1274     if (GetId() == id) {
1275         return { true, 0 };
1276     }
1277 
1278     const auto& node = ElementRegister::GetInstance()->GetUINodeById(id);
1279     if (!node) {
1280         return { false, 0 };
1281     }
1282 
1283     if (node && (node->GetTag() == GetTag())) {
1284         return { false, 1 };
1285     }
1286 
1287     int32_t count = 0;
1288     for (const auto& child : GetChildren()) {
1289         auto res = child->GetChildFlatIndex(id);
1290         if (res.first) {
1291             return { true, count + res.second };
1292         }
1293         count += res.second;
1294     }
1295     return { false, count };
1296 }
1297 
MarkRemoving()1298 bool UINode::MarkRemoving()
1299 {
1300     bool pendingRemove = false;
1301     isRemoving_ = true;
1302     const auto children = GetChildren();
1303     for (const auto& child : children) {
1304         pendingRemove = child->MarkRemoving() || pendingRemove;
1305     }
1306     return pendingRemove;
1307 }
1308 
SetChildrenInDestroying()1309 void UINode::SetChildrenInDestroying()
1310 {
1311     auto children = GetChildren();
1312     if (children.empty()) {
1313         return;
1314     }
1315 
1316     for (const auto& child : children) {
1317         if (!child) {
1318             continue;
1319         }
1320         child->SetChildrenInDestroying();
1321         child->SetInDestroying();
1322     }
1323 }
1324 
AddDisappearingChild(const RefPtr<UINode> & child,uint32_t index,int32_t branchId)1325 void UINode::AddDisappearingChild(const RefPtr<UINode>& child, uint32_t index, int32_t branchId)
1326 {
1327     if (child->isDisappearing_) {
1328         // if child is already disappearing, remove it from disappearingChildren_ first
1329         auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
1330             [child](const auto& tup) { return std::get<0>(tup) == child; });
1331         if (it != disappearingChildren_.end()) {
1332             disappearingChildren_.erase(it);
1333         }
1334     } else {
1335         // mark child as disappearing before adding to disappearingChildren_
1336         child->isDisappearing_ = true;
1337     }
1338     disappearingChildren_.emplace_back(child, index, branchId);
1339 }
1340 
RemoveDisappearingChild(const RefPtr<UINode> & child)1341 bool UINode::RemoveDisappearingChild(const RefPtr<UINode>& child)
1342 {
1343     // quick reject
1344     if (!child->isDisappearing_) {
1345         return false;
1346     }
1347     auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
1348         [child](const auto& tup) { return std::get<0>(tup) == child; });
1349     if (it == disappearingChildren_.end()) {
1350         return false;
1351     }
1352     disappearingChildren_.erase(it);
1353     child->isDisappearing_ = false;
1354     return true;
1355 }
1356 
OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)1357 void UINode::OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
1358 {
1359     GenerateOneDepthVisibleFrameWithTransition(visibleList);
1360 }
1361 
OnGenerateOneDepthVisibleFrameWithOffset(std::list<RefPtr<FrameNode>> & visibleList,OffsetF & offset)1362 void UINode::OnGenerateOneDepthVisibleFrameWithOffset(
1363     std::list<RefPtr<FrameNode>>& visibleList, OffsetF& offset)
1364 {
1365     GenerateOneDepthVisibleFrameWithOffset(visibleList, offset);
1366 }
1367 
RemoveImmediately() const1368 bool UINode::RemoveImmediately() const
1369 {
1370     auto children = GetChildren();
1371     return std::all_of(
1372                children.begin(), children.end(), [](const auto& child) { return child->RemoveImmediately(); }) &&
1373            std::all_of(disappearingChildren_.begin(), disappearingChildren_.end(),
1374                [](const auto& tup) { return std::get<0>(tup)->RemoveImmediately(); });
1375 }
1376 
GetPerformanceCheckData(PerformanceCheckNodeMap & nodeMap)1377 void UINode::GetPerformanceCheckData(PerformanceCheckNodeMap& nodeMap)
1378 {
1379     auto parent = GetParent();
1380     auto children = GetChildren();
1381     if (parent && parent->GetTag() == V2::JS_FOR_EACH_ETS_TAG) {
1382         // At this point, all of the children_
1383         // belong to the child nodes of syntaxItem
1384         for (const auto& child : children) {
1385             if (child->GetTag() == V2::COMMON_VIEW_ETS_TAG) {
1386                 auto grandChildren = child->GetChildren();
1387                 if (!grandChildren.empty()) {
1388                     auto begin = grandChildren.begin();
1389                     (*begin)->SetForeachItem();
1390                 }
1391             } else {
1392                 child->SetForeachItem();
1393             }
1394         }
1395     }
1396 
1397     if (tag_ == V2::COMMON_VIEW_ETS_TAG) {
1398         if (!children.empty()) {
1399             auto begin = children.begin();
1400             nodeInfo_->nodeTag = (*begin)->GetCustomTag();
1401         }
1402     } else {
1403         nodeInfo_->nodeTag = GetCustomTag();
1404     }
1405 
1406     nodeInfo_->pageDepth = depth_;
1407     nodeInfo_->childrenSize = children.size();
1408     if (isBuildByJS_) {
1409         nodeMap.insert({ GetId(), *(nodeInfo_) });
1410     }
1411     for (const auto& child : children) {
1412         // Recursively traverse the child nodes of each node
1413         child->GetPerformanceCheckData(nodeMap);
1414     }
1415 }
1416 
GetDisappearingChildById(const std::string & id,int32_t branchId) const1417 RefPtr<UINode> UINode::GetDisappearingChildById(const std::string& id, int32_t branchId) const
1418 {
1419     if (id.empty()) {
1420         return nullptr;
1421     }
1422     for (auto& [node, index, branch] : disappearingChildren_) {
1423         if (node->GetInspectorIdValue("") == id && branch == branchId) {
1424             return node;
1425         }
1426     }
1427     return nullptr;
1428 }
1429 
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)1430 RefPtr<UINode> UINode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
1431 {
1432     for (const auto& child : GetChildren()) {
1433         uint32_t count = static_cast<uint32_t>(child->FrameCount());
1434         if (count > index) {
1435             return child->GetFrameChildByIndex(index, needBuild, isCache, addToRenderTree);
1436         }
1437         index -= count;
1438     }
1439     return nullptr;
1440 }
1441 
GetFrameChildByIndexWithoutExpanded(uint32_t index)1442 RefPtr<UINode> UINode::GetFrameChildByIndexWithoutExpanded(uint32_t index)
1443 {
1444     for (const auto& child : GetChildren()) {
1445         uint32_t count = static_cast<uint32_t>(child->CurrentFrameCount());
1446         if (count > index) {
1447             return child->GetFrameChildByIndexWithoutExpanded(index);
1448         }
1449         index -= count;
1450     }
1451     return nullptr;
1452 }
1453 
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)1454 int32_t UINode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
1455 {
1456     int32_t index = 0;
1457     for (const auto& child : GetChildren()) {
1458         if (InstanceOf<FrameNode>(child)) {
1459             if (child == node) {
1460                 return index;
1461             } else {
1462                 index++;
1463                 continue;
1464             }
1465         }
1466         int32_t childIndex = child->GetFrameNodeIndex(node, isExpanded);
1467         if (childIndex >= 0) {
1468             return index + childIndex;
1469         }
1470         index += isExpanded ? child->FrameCount() : child->CurrentFrameCount();
1471     }
1472     return -1;
1473 }
1474 
DoRemoveChildInRenderTree(uint32_t index,bool isAll)1475 void UINode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
1476 {
1477     if (isAll) {
1478         for (const auto& child : children_) {
1479             child->DoRemoveChildInRenderTree(index, isAll);
1480         }
1481         return;
1482     }
1483     for (const auto& child : children_) {
1484         uint32_t count = static_cast<uint32_t>(child->FrameCount());
1485         if (count > index) {
1486             return child->DoRemoveChildInRenderTree(index);
1487         }
1488         index -= count;
1489     }
1490 }
1491 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)1492 void UINode::DoSetActiveChildRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
1493 {
1494     for (const auto& child : children_) {
1495         uint32_t count = static_cast<uint32_t>(child->FrameCount());
1496         child->DoSetActiveChildRange(start, end, cacheStart, cacheEnd, showCache);
1497         start -= static_cast<int32_t>(count);
1498         end -= static_cast<int32_t>(count);
1499     }
1500 }
1501 
OnSetCacheCount(int32_t cacheCount,const std::optional<LayoutConstraintF> & itemConstraint)1502 void UINode::OnSetCacheCount(int32_t cacheCount, const std::optional<LayoutConstraintF>& itemConstraint)
1503 {
1504     for (const auto& child : GetChildren()) {
1505         child->OnSetCacheCount(cacheCount, itemConstraint);
1506     }
1507 }
1508 
GetCurrentCustomNodeInfo()1509 std::string UINode::GetCurrentCustomNodeInfo()
1510 {
1511     auto parent = AceType::Claim(this);
1512     std::string extraInfo;
1513     while (parent) {
1514         if (InstanceOf<CustomNode>(parent)) {
1515             auto custom = DynamicCast<CustomNode>(parent);
1516             auto list = custom->GetExtraInfos();
1517             for (const auto& child : list) {
1518                 extraInfo.append("    ")
1519                     .append("at (")
1520                     .append(child.page)
1521                     .append(":")
1522                     .append(std::to_string(child.line))
1523                     .append(":")
1524                     .append(std::to_string(child.col))
1525                     .append(")\n");
1526             }
1527             break;
1528         }
1529         parent = parent->GetParent();
1530     }
1531     return extraInfo;
1532 }
1533 
GenerateAccessibilityId()1534 int64_t UINode::GenerateAccessibilityId()
1535 {
1536     return currentAccessibilityId_++;
1537 }
1538 
GetNodeStatus() const1539 NodeStatus UINode::GetNodeStatus() const
1540 {
1541     return nodeStatus_;
1542 }
1543 
SetParentLayoutConstraint(const SizeF & size) const1544 bool UINode::SetParentLayoutConstraint(const SizeF& size) const
1545 {
1546     auto children = GetChildren();
1547     return std::any_of(children.begin(), children.end(),
1548         [size](const RefPtr<UINode>& child) { return child->SetParentLayoutConstraint(size); });
1549 }
1550 
UpdateNodeStatus(NodeStatus nodeStatus)1551 void UINode::UpdateNodeStatus(NodeStatus nodeStatus)
1552 {
1553     if (nodeStatus_ == nodeStatus) {
1554         return;
1555     }
1556     nodeStatus_ = nodeStatus;
1557     OnAttachToBuilderNode(nodeStatus_);
1558     for (const auto& child : children_) {
1559         child->UpdateNodeStatus(nodeStatus_);
1560     }
1561 }
1562 
SetIsRootBuilderNode(bool isRootBuilderNode)1563 void UINode::SetIsRootBuilderNode(bool isRootBuilderNode)
1564 {
1565     isRootBuilderNode_ = isRootBuilderNode;
1566 }
1567 
GetIsRootBuilderNode() const1568 bool UINode::GetIsRootBuilderNode() const
1569 {
1570     return isRootBuilderNode_;
1571 }
1572 
1573 // Collects  all the child elements of "children" in a recursive manner
1574 // Fills the "removedElmtId" list with the collected child elements
CollectRemovedChildren(const std::list<RefPtr<UINode>> & children,std::list<int32_t> & removedElmtId,bool isEntry)1575 void UINode::CollectRemovedChildren(const std::list<RefPtr<UINode>>& children,
1576     std::list<int32_t>& removedElmtId, bool isEntry)
1577 {
1578     auto greatOrEqualApi13 = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN);
1579     for (auto const& child : children) {
1580         bool needByTransition = child->IsDisappearing();
1581         if (greatOrEqualApi13) {
1582             needByTransition = isEntry && child->IsDisappearing() && child->GetInspectorIdValue("") != "";
1583         }
1584         if (!needByTransition && child->GetTag() != V2::RECYCLE_VIEW_ETS_TAG && !child->GetIsRootBuilderNode()) {
1585             CollectRemovedChild(child, removedElmtId);
1586         }
1587     }
1588     if (isEntry) {
1589         children_.clear();
1590     }
1591 }
1592 
CollectRemovedChild(const RefPtr<UINode> & child,std::list<int32_t> & removedElmtId)1593 void UINode::CollectRemovedChild(const RefPtr<UINode>& child, std::list<int32_t>& removedElmtId)
1594 {
1595     removedElmtId.emplace_back(child->GetId());
1596     // Fetch all the child elementIDs recursively
1597     if (child->GetTag() != V2::JS_VIEW_ETS_TAG) {
1598         // add CustomNode but do not recurse into its children
1599         // add node create by BuilderNode do not recurse into its children
1600         CollectRemovedChildren(child->GetChildren(), removedElmtId, false);
1601     }
1602 }
1603 
PaintDebugBoundaryTreeAll(bool flag)1604 void UINode::PaintDebugBoundaryTreeAll(bool flag)
1605 {
1606     PaintDebugBoundary(flag);
1607     for (const auto& child : GetChildren()) {
1608         child->PaintDebugBoundaryTreeAll(flag);
1609     }
1610 }
1611 
GetPageNodeCountAndDepth(int32_t * count,int32_t * depth)1612 void UINode::GetPageNodeCountAndDepth(int32_t* count, int32_t* depth)
1613 {
1614     auto children = GetChildren();
1615     if (*depth < depth_) {
1616         *depth = depth_;
1617     }
1618     if (InstanceOf<FrameNode>(this)) {
1619         (*count)++;
1620     }
1621 
1622     for (const auto& child : children) {
1623         child->GetPageNodeCountAndDepth(count, depth);
1624     }
1625 }
1626 
DFSAllChild(const RefPtr<UINode> & root,std::vector<RefPtr<UINode>> & res)1627 void UINode::DFSAllChild(const RefPtr<UINode>& root, std::vector<RefPtr<UINode>>& res)
1628 {
1629     CHECK_NULL_VOID(root);
1630     if (root->GetChildren().empty()) {
1631         res.emplace_back(root);
1632     }
1633     for (const auto& child : root->GetChildren()) {
1634         DFSAllChild(child, res);
1635     }
1636 }
1637 
IsContextTransparent()1638 bool UINode::IsContextTransparent()
1639 {
1640     for (const auto& item : GetChildren()) {
1641         if (!item->IsContextTransparent()) {
1642             return false;
1643         }
1644     }
1645     return true;
1646 }
1647 
GetInspectorValue()1648 void UINode::GetInspectorValue()
1649 {
1650     for (const auto& item : GetChildren()) {
1651         item->GetInspectorValue();
1652     }
1653 }
1654 
ClearSubtreeLayoutAlgorithm(bool includeSelf,bool clearEntireTree)1655 void UINode::ClearSubtreeLayoutAlgorithm(bool includeSelf, bool clearEntireTree)
1656 {
1657     for (const auto& child : GetChildren()) {
1658         child->ClearSubtreeLayoutAlgorithm(includeSelf, clearEntireTree);
1659     }
1660 }
1661 
NotifyWebPattern(bool isRegister)1662 void UINode::NotifyWebPattern(bool isRegister)
1663 {
1664     for (const auto& item : GetChildren()) {
1665         item->NotifyWebPattern(isRegister);
1666     }
1667 }
1668 
GetContainerComponentText(std::string & text)1669 void UINode::GetContainerComponentText(std::string& text)
1670 {
1671     for (const auto& child : GetChildren()) {
1672         if (InstanceOf<FrameNode>(child) && child->GetTag() == V2::TEXT_ETS_TAG) {
1673             auto frameChild = DynamicCast<FrameNode>(child);
1674             auto pattern = frameChild->GetPattern();
1675             CHECK_NULL_VOID(pattern);
1676             auto layoutProperty = pattern->GetLayoutProperty<TextLayoutProperty>();
1677             CHECK_NULL_VOID(layoutProperty);
1678             text = layoutProperty->GetContent().value_or("");
1679             break;
1680         }
1681         child->GetContainerComponentText(text);
1682     }
1683 }
1684 
CalcAbsPosition(int32_t changeIdx,int64_t id) const1685 int32_t UINode::CalcAbsPosition(int32_t changeIdx, int64_t id) const
1686 {
1687     int32_t updateFrom = 0;
1688     for (const auto& child : GetChildren()) {
1689         if (child->GetAccessibilityId() == id) {
1690             updateFrom += changeIdx;
1691             break;
1692         }
1693         int32_t count = child->FrameCount();
1694         updateFrom += count;
1695     }
1696     return updateFrom;
1697 }
1698 
NotifyChange(int32_t changeIdx,int32_t count,int64_t id,NotificationType notificationType)1699 void UINode::NotifyChange(int32_t changeIdx, int32_t count, int64_t id, NotificationType notificationType)
1700 {
1701     int32_t updateFrom = CalcAbsPosition(changeIdx, id);
1702     auto accessibilityId = GetAccessibilityId();
1703     auto parent = GetParent();
1704     if (parent) {
1705         parent->NotifyChange(updateFrom, count, accessibilityId, notificationType);
1706     }
1707 }
1708 } // namespace OHOS::Ace::NG
1709