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/property/layout_constraint.h"
31 #include "core/components_v2/inspector/inspector_constants.h"
32 #include "core/pipeline/base/element_register.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34
35 namespace OHOS::Ace::NG {
36
37 thread_local int64_t UINode::currentAccessibilityId_ = 0;
38
UINode(const std::string & tag,int32_t nodeId,bool isRoot)39 UINode::UINode(const std::string& tag, int32_t nodeId, bool isRoot)
40 : tag_(tag), nodeId_(nodeId), accessibilityId_(currentAccessibilityId_++), isRoot_(isRoot)
41 {
42 if (AceChecker::IsPerformanceCheckEnabled()) {
43 auto pos = EngineHelper::GetPositionOnJsCode();
44 nodeInfo_ = std::make_unique<PerformanceCheckNode>();
45 nodeInfo_->codeRow = pos.first;
46 nodeInfo_->codeCol = pos.second;
47 }
48 #ifdef UICAST_COMPONENT_SUPPORTED
49 do {
50 auto container = Container::Current();
51 CHECK_NULL_BREAK(container);
52 auto distributedUI = container->GetDistributedUI();
53 CHECK_NULL_BREAK(distributedUI);
54 distributedUI->AddNewNode(nodeId_);
55 } while (false);
56 #endif
57 nodeStatus_ = ViewStackProcessor::GetInstance()->IsBuilderNode() ? NodeStatus::BUILDER_NODE_OFF_MAINTREE
58 : NodeStatus::NORMAL_NODE;
59 }
60
~UINode()61 UINode::~UINode()
62 {
63 #ifdef UICAST_COMPONENT_SUPPORTED
64 do {
65 auto container = Container::Current();
66 CHECK_NULL_BREAK(container);
67 auto distributedUI = container->GetDistributedUI();
68 CHECK_NULL_BREAK(distributedUI);
69 if (hostPageId_ == distributedUI->GetCurrentPageId()) {
70 distributedUI->AddDeletedNode(nodeId_);
71 }
72 } while (false);
73 #endif
74
75 if (!removeSilently_) {
76 ElementRegister::GetInstance()->RemoveItem(nodeId_, tag_);
77 } else {
78 ElementRegister::GetInstance()->RemoveItemSilently(nodeId_);
79 }
80 if (!onMainTree_) {
81 return;
82 }
83 onMainTree_ = false;
84 if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
85 nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
86 }
87 }
88
AddChild(const RefPtr<UINode> & child,int32_t slot,bool silently,bool addDefaultTransition)89 void UINode::AddChild(const RefPtr<UINode>& child, int32_t slot, bool silently, bool addDefaultTransition)
90 {
91 CHECK_NULL_VOID(child);
92 auto it = std::find(children_.begin(), children_.end(), child);
93 if (it != children_.end()) {
94 return;
95 }
96
97 // remove from disappearing children
98 RemoveDisappearingChild(child);
99 it = children_.begin();
100 std::advance(it, slot);
101 DoAddChild(it, child, silently, addDefaultTransition);
102 }
103
AddChildAfter(const RefPtr<UINode> & child,const RefPtr<UINode> & siblingNode)104 void UINode::AddChildAfter(const RefPtr<UINode>& child, const RefPtr<UINode>& siblingNode)
105 {
106 CHECK_NULL_VOID(child);
107 CHECK_NULL_VOID(siblingNode);
108 auto it = std::find(children_.begin(), children_.end(), child);
109 if (it != children_.end()) {
110 LOGW("Child node already exists. Existing child nodeId %{public}d, add %{public}s child nodeId nodeId "
111 "%{public}d",
112 (*it)->GetId(), child->GetTag().c_str(), child->GetId());
113 return;
114 }
115 // remove from disappearing children
116 RemoveDisappearingChild(child);
117 auto siblingNodeIter = std::find(children_.begin(), children_.end(), siblingNode);
118 if (siblingNodeIter != children_.end()) {
119 DoAddChild(++siblingNodeIter, child, false);
120 return;
121 }
122 it = children_.begin();
123 std::advance(it, -1);
124 DoAddChild(it, child, false);
125 }
126
RemoveChild(const RefPtr<UINode> & child,bool allowTransition)127 std::list<RefPtr<UINode>>::iterator UINode::RemoveChild(const RefPtr<UINode>& child, bool allowTransition)
128 {
129 CHECK_NULL_RETURN(child, children_.end());
130
131 auto iter = std::find(children_.begin(), children_.end(), child);
132 if (iter == children_.end()) {
133 return children_.end();
134 }
135 // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to the
136 // disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved until the
137 // transition has finished. We can then perform the necessary cleanup after the transition is complete.
138 if ((*iter)->OnRemoveFromParent(allowTransition)) {
139 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
140 RemoveDisappearingChild(child);
141 } else {
142 // else move child into disappearing children, skip syncing render tree
143 AddDisappearingChild(child, std::distance(children_.begin(), iter));
144 }
145 MarkNeedSyncRenderTree(true);
146 auto result = children_.erase(iter);
147 return result;
148 }
149
RemoveChildAndReturnIndex(const RefPtr<UINode> & child)150 int32_t UINode::RemoveChildAndReturnIndex(const RefPtr<UINode>& child)
151 {
152 auto result = RemoveChild(child);
153 return std::distance(children_.begin(), result);
154 }
155
RemoveChildAtIndex(int32_t index)156 void UINode::RemoveChildAtIndex(int32_t index)
157 {
158 auto children = GetChildren();
159 if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
160 return;
161 }
162 auto iter = children.begin();
163 std::advance(iter, index);
164 RemoveChild(*iter);
165 }
166
GetChildAtIndex(int32_t index) const167 RefPtr<UINode> UINode::GetChildAtIndex(int32_t index) const
168 {
169 auto children = GetChildren();
170 if ((index < 0) || (index >= static_cast<int32_t>(children.size()))) {
171 return nullptr;
172 }
173 auto iter = children.begin();
174 std::advance(iter, index);
175 if (iter != children.end()) {
176 return *iter;
177 }
178 return nullptr;
179 }
180
GetChildIndex(const RefPtr<UINode> & child) const181 int32_t UINode::GetChildIndex(const RefPtr<UINode>& child) const
182 {
183 int32_t index = 0;
184 for (const auto& iter : GetChildren()) {
185 if (iter == child) {
186 return index;
187 }
188 index++;
189 }
190 return -1;
191 }
192
ReplaceChild(const RefPtr<UINode> & oldNode,const RefPtr<UINode> & newNode)193 void UINode::ReplaceChild(const RefPtr<UINode>& oldNode, const RefPtr<UINode>& newNode)
194 {
195 if (!oldNode) {
196 if (newNode) {
197 AddChild(newNode);
198 }
199 return;
200 }
201
202 auto iter = RemoveChild(oldNode);
203 DoAddChild(iter, newNode, false, false);
204 }
205
Clean(bool cleanDirectly,bool allowTransition)206 void UINode::Clean(bool cleanDirectly, bool allowTransition)
207 {
208 bool needSyncRenderTree = false;
209 int32_t index = 0;
210 for (const auto& child : children_) {
211 // traverse down the child subtree to mark removing and find needs to hold subtree, if found add it to pending
212 if (!cleanDirectly && child->MarkRemoving()) {
213 ElementRegister::GetInstance()->AddPendingRemoveNode(child);
214 }
215 // If the child is undergoing a disappearing transition, rather than simply removing it, we should move it to
216 // the disappearing children. This ensures that the child remains alive and the tree hierarchy is preserved
217 // until the transition has finished. We can then perform the necessary cleanup after the transition is
218 // complete.
219 if (child->OnRemoveFromParent(allowTransition)) {
220 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
221 RemoveDisappearingChild(child);
222 needSyncRenderTree = true;
223 } else {
224 // else move child into disappearing children, skip syncing render tree
225 AddDisappearingChild(child, index);
226 }
227 ++index;
228 }
229 children_.clear();
230 MarkNeedSyncRenderTree(true);
231 }
232
MountToParent(const RefPtr<UINode> & parent,int32_t slot,bool silently,bool addDefaultTransition)233 void UINode::MountToParent(const RefPtr<UINode>& parent, int32_t slot, bool silently, bool addDefaultTransition)
234 {
235 CHECK_NULL_VOID(parent);
236 parent->AddChild(AceType::Claim(this), slot, silently, addDefaultTransition);
237 if (parent->IsInDestroying()) {
238 parent->SetChildrenInDestroying();
239 }
240 if (parent->GetPageId() != 0) {
241 SetHostPageId(parent->GetPageId());
242 }
243 }
244
UpdateConfigurationUpdate(const ConfigurationChange & configurationChange)245 void UINode::UpdateConfigurationUpdate(const ConfigurationChange& configurationChange)
246 {
247 OnConfigurationUpdate(configurationChange);
248 if (needCallChildrenUpdate_) {
249 auto children = GetChildren();
250 for (const auto& child : children) {
251 if (!child) {
252 continue;
253 }
254 child->UpdateConfigurationUpdate(configurationChange);
255 }
256 }
257 }
258
OnRemoveFromParent(bool allowTransition)259 bool UINode::OnRemoveFromParent(bool allowTransition)
260 {
261 // The recursive flag will used by RenderContext, if recursive flag is false,
262 // it may trigger transition
263 DetachFromMainTree(!allowTransition);
264 if (allowTransition && !RemoveImmediately()) {
265 return false;
266 }
267 ResetParent();
268 return true;
269 }
270
ResetParent()271 void UINode::ResetParent()
272 {
273 parent_.Reset();
274 depth_ = -1;
275 }
276
DoAddChild(std::list<RefPtr<UINode>>::iterator & it,const RefPtr<UINode> & child,bool silently,bool addDefaultTransition)277 void UINode::DoAddChild(
278 std::list<RefPtr<UINode>>::iterator& it, const RefPtr<UINode>& child, bool silently, bool addDefaultTransition)
279 {
280 children_.insert(it, child);
281
282 child->SetParent(Claim(this));
283 child->SetDepth(GetDepth() + 1);
284 if (nodeStatus_ != NodeStatus::NORMAL_NODE) {
285 child->UpdateNodeStatus(nodeStatus_);
286 }
287
288 if (!silently && onMainTree_) {
289 child->AttachToMainTree(!addDefaultTransition);
290 }
291 MarkNeedSyncRenderTree(true);
292 }
293
GetFocusParent() const294 RefPtr<FrameNode> UINode::GetFocusParent() const
295 {
296 auto parentUi = GetParent();
297 while (parentUi) {
298 auto parentFrame = AceType::DynamicCast<FrameNode>(parentUi);
299 if (!parentFrame) {
300 parentUi = parentUi->GetParent();
301 continue;
302 }
303 auto type = parentFrame->GetFocusType();
304 if (type == FocusType::SCOPE) {
305 return parentFrame;
306 }
307 if (type == FocusType::NODE) {
308 return nullptr;
309 }
310 parentUi = parentUi->GetParent();
311 }
312 return nullptr;
313 }
314
GetFirstFocusHubChild() const315 RefPtr<FocusHub> UINode::GetFirstFocusHubChild() const
316 {
317 const auto* frameNode = AceType::DynamicCast<FrameNode>(this);
318 if (frameNode) {
319 auto focusHub = frameNode->GetFocusHub();
320 if (focusHub && focusHub->GetFocusType() != FocusType::DISABLE) {
321 return focusHub;
322 }
323 }
324 for (const auto& child : GetChildren()) {
325 auto focusHub = child->GetFirstFocusHubChild();
326 if (focusHub) {
327 return focusHub;
328 }
329 }
330 return nullptr;
331 }
332
GetFocusChildren(std::list<RefPtr<FrameNode>> & children) const333 void UINode::GetFocusChildren(std::list<RefPtr<FrameNode>>& children) const
334 {
335 auto uiChildren = GetChildren();
336 for (const auto& uiChild : uiChildren) {
337 auto frameChild = AceType::DynamicCast<FrameNode>(uiChild);
338 if (frameChild && frameChild->GetFocusType() != FocusType::DISABLE) {
339 children.emplace_back(frameChild);
340 } else {
341 uiChild->GetFocusChildren(children);
342 }
343 }
344 }
345
AttachToMainTree(bool recursive)346 void UINode::AttachToMainTree(bool recursive)
347 {
348 if (onMainTree_) {
349 return;
350 }
351 onMainTree_ = true;
352 if (nodeStatus_ == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
353 nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE;
354 }
355 isRemoving_ = false;
356 OnAttachToMainTree(recursive);
357 // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
358 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
359 for (const auto& child : GetChildren()) {
360 child->AttachToMainTree(isRecursive);
361 }
362 }
363
DetachFromMainTree(bool recursive)364 void UINode::DetachFromMainTree(bool recursive)
365 {
366 if (!onMainTree_) {
367 return;
368 }
369 onMainTree_ = false;
370 if (nodeStatus_ == NodeStatus::BUILDER_NODE_ON_MAINTREE) {
371 nodeStatus_ = NodeStatus::BUILDER_NODE_OFF_MAINTREE;
372 }
373 isRemoving_ = true;
374 OnDetachFromMainTree(recursive);
375 // if recursive = false, recursively call DetachFromMainTree(false), until we reach the first FrameNode.
376 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
377 for (const auto& child : GetChildren()) {
378 child->DetachFromMainTree(isRecursive);
379 }
380 }
381
ProcessOffscreenTask(bool recursive)382 void UINode::ProcessOffscreenTask(bool recursive)
383 {
384 if (useOffscreenProcess_) {
385 return;
386 }
387 useOffscreenProcess_ = true;
388 OnOffscreenProcess(recursive);
389 // if recursive = false, recursively call AttachToMainTree(false), until we reach the first FrameNode.
390 bool isRecursive = recursive || AceType::InstanceOf<FrameNode>(this);
391 for (const auto& child : GetChildren()) {
392 child->ProcessOffscreenTask(isRecursive);
393 }
394 }
395
MovePosition(int32_t slot)396 void UINode::MovePosition(int32_t slot)
397 {
398 auto parentNode = parent_.Upgrade();
399 CHECK_NULL_VOID(parentNode);
400
401 auto self = AceType::Claim(this);
402 auto& children = parentNode->children_;
403 auto it = children.end();
404 if (slot >= 0 && static_cast<size_t>(slot) < children.size()) {
405 it = children.begin();
406 std::advance(it, slot);
407 if ((it != children.end()) && (*it == this)) {
408 // Already at the right place
409 return;
410 }
411
412 auto itSelf = std::find(it, children.end(), self);
413 if (itSelf != children.end()) {
414 children.erase(itSelf);
415 } else {
416 children.remove(self);
417 ++it;
418 }
419 } else {
420 children.remove(self);
421 }
422 children.insert(it, self);
423 parentNode->MarkNeedSyncRenderTree(true);
424 }
425
UpdateLayoutPropertyFlag()426 void UINode::UpdateLayoutPropertyFlag()
427 {
428 for (const auto& child : GetChildren()) {
429 child->UpdateLayoutPropertyFlag();
430 }
431 }
432
AdjustParentLayoutFlag(PropertyChangeFlag & flag)433 void UINode::AdjustParentLayoutFlag(PropertyChangeFlag& flag)
434 {
435 for (const auto& child : GetChildren()) {
436 child->AdjustParentLayoutFlag(flag);
437 }
438 }
439
MarkDirtyNode(PropertyChangeFlag extraFlag,bool childExpansiveAndMark)440 void UINode::MarkDirtyNode(PropertyChangeFlag extraFlag, bool childExpansiveAndMark)
441 {
442 for (const auto& child : GetChildren()) {
443 child->MarkDirtyNode(extraFlag, childExpansiveAndMark);
444 }
445 }
446
MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)447 void UINode::MarkNeedFrameFlushDirty(PropertyChangeFlag extraFlag)
448 {
449 auto parent = parent_.Upgrade();
450 if (parent) {
451 parent->MarkNeedFrameFlushDirty(extraFlag);
452 }
453 }
454
MarkNeedSyncRenderTree(bool needRebuild)455 void UINode::MarkNeedSyncRenderTree(bool needRebuild)
456 {
457 auto parent = parent_.Upgrade();
458 if (parent) {
459 parent->MarkNeedSyncRenderTree(needRebuild);
460 }
461 }
462
RebuildRenderContextTree()463 void UINode::RebuildRenderContextTree()
464 {
465 auto parent = parent_.Upgrade();
466 if (parent) {
467 parent->RebuildRenderContextTree();
468 }
469 }
OnDetachFromMainTree(bool)470 void UINode::OnDetachFromMainTree(bool) {}
471
OnAttachToMainTree(bool)472 void UINode::OnAttachToMainTree(bool)
473 {
474 useOffscreenProcess_ = false;
475 decltype(attachToMainTreeTasks_) tasks(std::move(attachToMainTreeTasks_));
476 for (const auto& task : tasks) {
477 if (task) {
478 task();
479 }
480 }
481 }
482
DumpViewDataPageNodes(RefPtr<ViewDataWrap> viewDataWrap)483 void UINode::DumpViewDataPageNodes(RefPtr<ViewDataWrap> viewDataWrap)
484 {
485 DumpViewDataPageNode(viewDataWrap);
486 for (const auto& item : GetChildren()) {
487 item->DumpViewDataPageNodes(viewDataWrap);
488 }
489 }
490
NeedRequestAutoSave()491 bool UINode::NeedRequestAutoSave()
492 {
493 if (CheckAutoSave()) {
494 return true;
495 }
496 for (const auto& item : GetChildren()) {
497 if (item->NeedRequestAutoSave()) {
498 return true;
499 }
500 }
501 return false;
502 }
503
DumpTree(int32_t depth)504 void UINode::DumpTree(int32_t depth)
505 {
506 if (DumpLog::GetInstance().GetDumpFile()) {
507 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
508 DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(GetDepth())));
509 DumpLog::GetInstance().AddDesc("AccessibilityId: " + std::to_string(accessibilityId_));
510 if (IsDisappearing()) {
511 DumpLog::GetInstance().AddDesc(std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
512 }
513 DumpInfo();
514 DumpLog::GetInstance().Append(depth, tag_, static_cast<int32_t>(GetChildren().size()));
515 }
516 for (const auto& item : GetChildren()) {
517 item->DumpTree(depth + 1);
518 }
519 for (const auto& [item, index] : disappearingChildren_) {
520 item->DumpTree(depth + 1);
521 }
522 auto frameNode = AceType::DynamicCast<FrameNode>(this);
523 if (frameNode && frameNode->GetOverlayNode()) {
524 frameNode->GetOverlayNode()->DumpTree(depth + 1);
525 }
526 }
527
DumpTreeById(int32_t depth,const std::string & id)528 bool UINode::DumpTreeById(int32_t depth, const std::string& id)
529 {
530 if (DumpLog::GetInstance().GetDumpFile() &&
531 (id == propInspectorId_.value_or("") || id == std::to_string(nodeId_))) {
532 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(nodeId_));
533 DumpLog::GetInstance().AddDesc(std::string("Depth: ").append(std::to_string(GetDepth())));
534 DumpLog::GetInstance().AddDesc(std::string("IsDisappearing: ").append(std::to_string(IsDisappearing())));
535 DumpAdvanceInfo();
536 DumpLog::GetInstance().Print(depth, tag_, static_cast<int32_t>(GetChildren().size()));
537 return true;
538 }
539 for (const auto& item : GetChildren()) {
540 if (item->DumpTreeById(depth + 1, id)) {
541 return true;
542 }
543 }
544 for (const auto& [item, index] : disappearingChildren_) {
545 if (item->DumpTreeById(depth + 1, id)) {
546 return true;
547 }
548 }
549 return false;
550 }
551
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)552 void UINode::AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
553 {
554 for (const auto& child : children_) {
555 if (!child->IsInDestroying()) {
556 child->AdjustLayoutWrapperTree(parent, forceMeasure, forceLayout);
557 }
558 }
559 }
560
GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>> & visibleList)561 void UINode::GenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>>& visibleList)
562 {
563 for (const auto& child : GetChildren()) {
564 child->OnGenerateOneDepthVisibleFrame(visibleList);
565 }
566 }
567
GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)568 void UINode::GenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
569 {
570 if (disappearingChildren_.empty()) {
571 // normal child
572 for (const auto& child : GetChildren()) {
573 child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
574 }
575 return;
576 }
577 // generate the merged list of children_ and disappearingChildren_
578 auto allChildren = GetChildren();
579 for (auto iter = disappearingChildren_.rbegin(); iter != disappearingChildren_.rend(); ++iter) {
580 auto& [disappearingChild, index] = *iter;
581 if (index >= allChildren.size()) {
582 allChildren.emplace_back(disappearingChild);
583 } else {
584 auto insertIter = allChildren.begin();
585 std::advance(insertIter, index);
586 allChildren.insert(insertIter, disappearingChild);
587 }
588 }
589 for (const auto& child : allChildren) {
590 child->OnGenerateOneDepthVisibleFrameWithTransition(visibleList);
591 }
592 }
593
GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>> & visibleList)594 void UINode::GenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>>& visibleList)
595 {
596 for (const auto& child : GetChildren()) {
597 child->OnGenerateOneDepthAllFrame(visibleList);
598 }
599 }
600
GetContext()601 RefPtr<PipelineContext> UINode::GetContext()
602 {
603 return PipelineContext::GetCurrentContext();
604 }
605
TouchTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,TouchTestResult & result,int32_t touchId,bool isDispatch)606 HitTestResult UINode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint,
607 const PointF& parentRevertPoint, TouchRestrict& touchRestrict, TouchTestResult& result, int32_t touchId,
608 bool isDispatch)
609 {
610 auto children = GetChildren();
611 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
612 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
613 auto& child = *iter;
614 auto hitResult =
615 child->TouchTest(globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, result, touchId);
616 if (hitResult == HitTestResult::STOP_BUBBLING) {
617 return HitTestResult::STOP_BUBBLING;
618 }
619 if (hitResult == HitTestResult::BUBBLING) {
620 hitTestResult = HitTestResult::BUBBLING;
621 }
622 }
623 return hitTestResult;
624 }
625
MouseTest(const PointF & globalPoint,const PointF & parentLocalPoint,MouseTestResult & onMouseResult,MouseTestResult & onHoverResult,RefPtr<FrameNode> & hoverNode)626 HitTestResult UINode::MouseTest(const PointF& globalPoint, const PointF& parentLocalPoint,
627 MouseTestResult& onMouseResult, MouseTestResult& onHoverResult, RefPtr<FrameNode>& hoverNode)
628 {
629 auto children = GetChildren();
630 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
631 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
632 auto& child = *iter;
633 auto hitResult = child->MouseTest(globalPoint, parentLocalPoint, onMouseResult, onHoverResult, hoverNode);
634 if (hitResult == HitTestResult::STOP_BUBBLING) {
635 return HitTestResult::STOP_BUBBLING;
636 }
637 if (hitResult == HitTestResult::BUBBLING) {
638 hitTestResult = HitTestResult::BUBBLING;
639 }
640 }
641 return hitTestResult;
642 }
643
AxisTest(const PointF & globalPoint,const PointF & parentLocalPoint,AxisTestResult & onAxisResult)644 HitTestResult UINode::AxisTest(const PointF& globalPoint, const PointF& parentLocalPoint, AxisTestResult& onAxisResult)
645 {
646 auto children = GetChildren();
647 HitTestResult hitTestResult = HitTestResult::OUT_OF_REGION;
648 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
649 auto& child = *iter;
650 auto hitResult = child->AxisTest(globalPoint, parentLocalPoint, onAxisResult);
651 if (hitResult == HitTestResult::STOP_BUBBLING) {
652 return HitTestResult::STOP_BUBBLING;
653 }
654 if (hitResult == HitTestResult::BUBBLING) {
655 hitTestResult = HitTestResult::BUBBLING;
656 }
657 }
658 return hitTestResult;
659 }
660
FrameCount() const661 int32_t UINode::FrameCount() const
662 {
663 return TotalChildCount();
664 }
665
TotalChildCount() const666 int32_t UINode::TotalChildCount() const
667 {
668 int32_t count = 0;
669 for (const auto& child : GetChildren()) {
670 count += child->FrameCount();
671 }
672 return count;
673 }
674
GetChildIndexById(int32_t id)675 int32_t UINode::GetChildIndexById(int32_t id)
676 {
677 int32_t pos = 0;
678 auto children = GetChildren();
679 auto iter = children.begin();
680 while (iter != children.end()) {
681 if (id == (*iter)->GetId()) {
682 return pos;
683 }
684 pos++;
685 iter++;
686 }
687 return -1;
688 }
689
CreateLayoutWrapper(bool forceMeasure,bool forceLayout)690 RefPtr<LayoutWrapperNode> UINode::CreateLayoutWrapper(bool forceMeasure, bool forceLayout)
691 {
692 if (GetChildren().empty()) {
693 return nullptr;
694 }
695
696 auto child = GetChildren().front();
697 while (!InstanceOf<FrameNode>(child)) {
698 auto children = child->GetChildren();
699 if (children.empty()) {
700 return nullptr;
701 }
702
703 child = children.front();
704 }
705
706 auto frameChild = DynamicCast<FrameNode>(child);
707 return frameChild ? frameChild->CreateLayoutWrapper(forceMeasure, forceLayout) : nullptr;
708 }
709
RenderCustomChild(int64_t deadline)710 bool UINode::RenderCustomChild(int64_t deadline)
711 {
712 for (const auto& child : GetChildren()) {
713 if (child && !child->RenderCustomChild(deadline)) {
714 return false;
715 }
716 }
717 return true;
718 }
719
Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)720 void UINode::Build(std::shared_ptr<std::list<ExtraInfo>> extraInfos)
721 {
722 for (const auto& child : GetChildren()) {
723 if (InstanceOf<CustomNode>(child)) {
724 auto custom = DynamicCast<CustomNode>(child);
725 if (custom->HasExtraInfo()) {
726 if (!extraInfos) {
727 extraInfos = std::make_shared<std::list<ExtraInfo>>();
728 }
729 extraInfos->emplace_front(custom->GetExtraInfo());
730 custom->Build(extraInfos);
731 extraInfos->pop_front();
732 } else {
733 custom->Build(extraInfos);
734 }
735 } else {
736 child->Build(extraInfos);
737 }
738 }
739 }
740
CreateExportTextureInfoIfNeeded()741 void UINode::CreateExportTextureInfoIfNeeded()
742 {
743 if (!exportTextureInfo_) {
744 exportTextureInfo_ = MakeRefPtr<ExportTextureInfo>();
745 }
746 }
747
IsNeedExportTexture() const748 bool UINode::IsNeedExportTexture() const
749 {
750 return exportTextureInfo_ && exportTextureInfo_->GetCurrentRenderType() == NodeRenderType::RENDER_TYPE_TEXTURE;
751 }
752
SetActive(bool active)753 void UINode::SetActive(bool active)
754 {
755 for (const auto& child : GetChildren()) {
756 child->SetActive(active);
757 }
758 }
759
SetJSViewActive(bool active)760 void UINode::SetJSViewActive(bool active)
761 {
762 for (const auto& child : GetChildren()) {
763 auto frameNodeChild = AceType::DynamicCast<FrameNode>(child);
764 // if child is framenode and its state is inactive, and the new state is active, then
765 // do not inform the state recursively
766 // List (active)
767 // |--ListItem(inActive)
768 // |--CustomComponent(fellow ListItem)
769 // if the List setActive(true) when doing some measuring or layout, ListItem is inActive, then
770 // the customComponent only follow the ListItem state changes
771 if (frameNodeChild && !frameNodeChild->IsActive() && active) {
772 return;
773 }
774 child->SetJSViewActive(active);
775 }
776 }
777
OnVisibleChange(bool isVisible)778 void UINode::OnVisibleChange(bool isVisible)
779 {
780 UpdateChildrenVisible(isVisible);
781 }
782
UpdateChildrenVisible(bool isVisible) const783 void UINode::UpdateChildrenVisible(bool isVisible) const
784 {
785 for (const auto& child : GetChildren()) {
786 if (InstanceOf<FrameNode>(child)) {
787 auto childLayoutProperty = DynamicCast<FrameNode>(child)->GetLayoutProperty();
788 if (childLayoutProperty &&
789 childLayoutProperty->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
790 // child is invisible, no need to update visible state.
791 continue;
792 }
793 }
794 child->OnVisibleChange(isVisible);
795 }
796 }
797
GetChildFlatIndex(int32_t id)798 std::pair<bool, int32_t> UINode::GetChildFlatIndex(int32_t id)
799 {
800 if (GetId() == id) {
801 return { true, 0 };
802 }
803
804 const auto& node = ElementRegister::GetInstance()->GetUINodeById(id);
805 if (!node) {
806 return { false, 0 };
807 }
808
809 if (node && (node->GetTag() == GetTag())) {
810 return { false, 1 };
811 }
812
813 int32_t count = 0;
814 for (const auto& child : GetChildren()) {
815 auto res = child->GetChildFlatIndex(id);
816 if (res.first) {
817 return { true, count + res.second };
818 }
819 count += res.second;
820 }
821 return { false, count };
822 }
823
824 // for Grid refresh GridItems
ChildrenUpdatedFrom(int32_t index)825 void UINode::ChildrenUpdatedFrom(int32_t index)
826 {
827 childrenUpdatedFrom_ = childrenUpdatedFrom_ >= 0 ? std::min(index, childrenUpdatedFrom_) : index;
828 }
829
MarkRemoving()830 bool UINode::MarkRemoving()
831 {
832 bool pendingRemove = false;
833 isRemoving_ = true;
834 const auto& children = GetChildren();
835 for (const auto& child : children) {
836 pendingRemove = child->MarkRemoving() || pendingRemove;
837 }
838 return pendingRemove;
839 }
840
SetChildrenInDestroying()841 void UINode::SetChildrenInDestroying()
842 {
843 auto children = GetChildren();
844 if (children.empty()) {
845 return;
846 }
847
848 for (const auto& child : children) {
849 if (!child) {
850 continue;
851 }
852 child->SetChildrenInDestroying();
853 child->SetInDestroying();
854 }
855 }
856
AddDisappearingChild(const RefPtr<UINode> & child,uint32_t index)857 void UINode::AddDisappearingChild(const RefPtr<UINode>& child, uint32_t index)
858 {
859 if (child->isDisappearing_) {
860 // if child is already disappearing, remove it from disappearingChildren_ first
861 auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
862 [child](const auto& pair) { return pair.first == child; });
863 if (it != disappearingChildren_.end()) {
864 disappearingChildren_.erase(it);
865 }
866 } else {
867 // mark child as disappearing before adding to disappearingChildren_
868 child->isDisappearing_ = true;
869 }
870 disappearingChildren_.emplace_back(child, index);
871 }
872
RemoveDisappearingChild(const RefPtr<UINode> & child)873 bool UINode::RemoveDisappearingChild(const RefPtr<UINode>& child)
874 {
875 // quick reject
876 if (!child->isDisappearing_) {
877 return false;
878 }
879 auto it = std::find_if(disappearingChildren_.begin(), disappearingChildren_.end(),
880 [child](const auto& pair) { return pair.first == child; });
881 if (it == disappearingChildren_.end()) {
882 return false;
883 }
884 disappearingChildren_.erase(it);
885 child->isDisappearing_ = false;
886 return true;
887 }
888
OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>> & visibleList)889 void UINode::OnGenerateOneDepthVisibleFrameWithTransition(std::list<RefPtr<FrameNode>>& visibleList)
890 {
891 GenerateOneDepthVisibleFrameWithTransition(visibleList);
892 }
893
RemoveImmediately() const894 bool UINode::RemoveImmediately() const
895 {
896 auto children = GetChildren();
897 return std::all_of(
898 children.begin(), children.end(), [](const auto& child) { return child->RemoveImmediately(); }) &&
899 std::all_of(disappearingChildren_.begin(), disappearingChildren_.end(),
900 [](const auto& pair) { return pair.first->RemoveImmediately(); });
901 }
902
GetPerformanceCheckData(PerformanceCheckNodeMap & nodeMap)903 void UINode::GetPerformanceCheckData(PerformanceCheckNodeMap& nodeMap)
904 {
905 auto parent = GetParent();
906 auto children = GetChildren();
907 if (parent && parent->GetTag() == V2::JS_FOR_EACH_ETS_TAG) {
908 // At this point, all of the children_
909 // belong to the child nodes of syntaxItem
910 for (const auto& child : children) {
911 if (child->GetTag() == V2::COMMON_VIEW_ETS_TAG) {
912 auto grandChildren = child->GetChildren();
913 if (!grandChildren.empty()) {
914 auto begin = grandChildren.begin();
915 (*begin)->SetForeachItem();
916 }
917 } else {
918 child->SetForeachItem();
919 }
920 }
921 }
922
923 if (tag_ == V2::COMMON_VIEW_ETS_TAG) {
924 if (!children.empty()) {
925 auto begin = children.begin();
926 nodeInfo_->nodeTag = (*begin)->GetCustomTag();
927 }
928 } else {
929 nodeInfo_->nodeTag = GetCustomTag();
930 }
931
932 nodeInfo_->pageDepth = depth_;
933 nodeInfo_->childrenSize = children.size();
934 if (isBuildByJS_) {
935 nodeMap.insert({ GetId(), *(nodeInfo_) });
936 }
937 for (const auto& child : children) {
938 // Recursively traverse the child nodes of each node
939 child->GetPerformanceCheckData(nodeMap);
940 }
941 }
942
GetDisappearingChildById(const std::string & id) const943 RefPtr<UINode> UINode::GetDisappearingChildById(const std::string& id) const
944 {
945 if (id.empty()) {
946 return nullptr;
947 }
948 for (auto& [node, index] : disappearingChildren_) {
949 if (node->GetInspectorIdValue("") == id) {
950 return node;
951 }
952 }
953 return nullptr;
954 }
955
GetFrameChildByIndex(uint32_t index,bool needBuild)956 RefPtr<UINode> UINode::GetFrameChildByIndex(uint32_t index, bool needBuild)
957 {
958 for (const auto& child : GetChildren()) {
959 uint32_t count = static_cast<uint32_t>(child->FrameCount());
960 if (count > index) {
961 return child->GetFrameChildByIndex(index, needBuild);
962 }
963 index -= count;
964 }
965 return nullptr;
966 }
967
DoRemoveChildInRenderTree(uint32_t index,bool isAll)968 void UINode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
969 {
970 if (isAll) {
971 for (const auto& child : children_) {
972 child->DoRemoveChildInRenderTree(index, isAll);
973 }
974 return;
975 }
976 for (const auto& child : children_) {
977 uint32_t count = static_cast<uint32_t>(child->FrameCount());
978 if (count > index) {
979 return child->DoRemoveChildInRenderTree(index);
980 }
981 index -= count;
982 }
983 }
984
DoSetActiveChildRange(int32_t start,int32_t end)985 void UINode::DoSetActiveChildRange(int32_t start, int32_t end)
986 {
987 for (const auto& child : children_) {
988 uint32_t count = static_cast<uint32_t>(child->FrameCount());
989 child->DoSetActiveChildRange(start, end);
990 start -= static_cast<int32_t>(count);
991 end -= static_cast<int32_t>(count);
992 }
993 }
994
OnSetCacheCount(int32_t cacheCount,const std::optional<LayoutConstraintF> & itemConstraint)995 void UINode::OnSetCacheCount(int32_t cacheCount, const std::optional<LayoutConstraintF>& itemConstraint)
996 {
997 for (const auto& child : GetChildren()) {
998 child->OnSetCacheCount(cacheCount, itemConstraint);
999 }
1000 }
1001
GetCurrentCustomNodeInfo()1002 std::string UINode::GetCurrentCustomNodeInfo()
1003 {
1004 auto parent = AceType::Claim(this);
1005 std::string extraInfo;
1006 while (parent) {
1007 if (InstanceOf<CustomNode>(parent)) {
1008 auto custom = DynamicCast<CustomNode>(parent);
1009 auto list = custom->GetExtraInfos();
1010 for (const auto& child : list) {
1011 extraInfo.append(" ").append("at (").append(child.page).append(":")
1012 .append(std::to_string(child.line)).append(")\n");
1013 }
1014 break;
1015 }
1016 parent = parent->GetParent();
1017
1018 }
1019 return extraInfo;
1020 }
1021
GenerateAccessibilityId()1022 int64_t UINode::GenerateAccessibilityId()
1023 {
1024 return currentAccessibilityId_++;
1025 }
1026
GetNodeStatus() const1027 NodeStatus UINode::GetNodeStatus() const
1028 {
1029 return nodeStatus_;
1030 }
1031
SetParentLayoutConstraint(const SizeF & size) const1032 bool UINode::SetParentLayoutConstraint(const SizeF& size) const
1033 {
1034 auto children = GetChildren();
1035 return std::any_of(children.begin(), children.end(),
1036 [size](const RefPtr<UINode>& child) { return child->SetParentLayoutConstraint(size); });
1037 }
1038
UpdateNodeStatus(NodeStatus nodeStatus)1039 void UINode::UpdateNodeStatus(NodeStatus nodeStatus)
1040 {
1041 nodeStatus_ = nodeStatus;
1042 for (const auto& child : children_) {
1043 if (child->GetNodeStatus() == nodeStatus_) {
1044 continue;
1045 }
1046 child->OnAttachToBuilderNode(nodeStatus_);
1047 child->UpdateNodeStatus(nodeStatus_);
1048 }
1049 }
1050 } // namespace OHOS::Ace::NG
1051