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