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