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