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