1 /*
2 * Copyright (c) 2025 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
16 #include "core/components_ng/base/node_render_status_monitor.h"
17
18 #include "ui/base/utils/utils.h"
19
20 #include "core/components_ng/base/frame_node.h"
21
22 namespace OHOS::Ace::NG {
23 namespace {
24 constexpr size_t MAX_NODE_RENDER_STATE_LISTENERS = 64;
25 } // namespace
26
IsRegisterNodeRenderStateChangeCallbackExceedLimit()27 bool NodeRenderStatusMonitor::IsRegisterNodeRenderStateChangeCallbackExceedLimit()
28 {
29 return nodeRenderStatusListeners_.size() >= MAX_NODE_RENDER_STATE_LISTENERS;
30 }
31
RegisterNodeRenderStatusListener(FrameNode * frameNode,NodeRenderStatusHandleFunc && func,MonitorSourceType type)32 MonitorRegisterResult NodeRenderStatusMonitor::RegisterNodeRenderStatusListener(
33 FrameNode* frameNode, NodeRenderStatusHandleFunc&& func, MonitorSourceType type)
34 {
35 MonitorRegisterResult result;
36 CHECK_NULL_RETURN(frameNode, result);
37 CHECK_NULL_RETURN(func, result);
38 if (nodeRenderStatusListeners_.size() >= MAX_NODE_RENDER_STATE_LISTENERS) {
39 return result;
40 }
41 auto state = GetNodeCurrentRenderState(frameNode);
42 auto iter = nodeRenderStatusListeners_.find(frameNode);
43 if (iter == nodeRenderStatusListeners_.end()) {
44 auto id = NodeRenderStatusMonitor::GenerateId();
45 auto listener = std::make_shared<NodeRenderStatusListener>(type, id, std::move(func));
46 auto sourceListener = std::make_shared<NodeRenderStatusSourceListener>(
47 state, std::list<std::shared_ptr<NodeRenderStatusListener>>({ listener }));
48 nodeRenderStatusListeners_.emplace(frameNode, std::move(sourceListener));
49 return { id, state };
50 }
51 CHECK_NULL_RETURN(iter->second, result);
52 auto& holder = iter->second->nodeRenderStatusListeners;
53 // OBSERVER can only be registered once
54 if (type == MonitorSourceType::OBSERVER &&
55 std::any_of(holder.begin(), holder.end(), [](const std::shared_ptr<NodeRenderStatusListener>& listener) {
56 return listener->sourceType == MonitorSourceType::OBSERVER;
57 })) {
58 return result;
59 }
60
61 auto id = NodeRenderStatusMonitor::GenerateId();
62 holder.emplace_back(std::make_shared<NodeRenderStatusListener>(type, id, std::move(func)));
63 return { id, state };
64 }
65
UnRegisterNodeRenderStatusListener(FrameNode * frameNode,int32_t id)66 void NodeRenderStatusMonitor::UnRegisterNodeRenderStatusListener(FrameNode* frameNode, int32_t id)
67 {
68 CHECK_NULL_VOID(frameNode);
69 auto iter = nodeRenderStatusListeners_.find(frameNode);
70 if (iter == nodeRenderStatusListeners_.end()) {
71 return;
72 }
73 CHECK_NULL_VOID(iter->second);
74 auto& holder = iter->second->nodeRenderStatusListeners;
75
76 holder.erase(
77 std::remove_if(
78 holder.begin(),
79 holder.end(),
80 [id](const std::shared_ptr<NodeRenderStatusListener>& registeredListener) {
81 return registeredListener->id == id;
82 }),
83 holder.end());
84 if (holder.empty()) {
85 nodeRenderStatusListeners_.erase(frameNode);
86 }
87 }
88
WalkThroughAncestorForStateListener()89 void NodeRenderStatusMonitor::WalkThroughAncestorForStateListener()
90 {
91 ACE_FUNCTION_TRACE();
92 std::vector<std::pair<FrameNode*, NodeRenderStatusHandleFunc>> inCallbacks;
93 std::vector<std::pair<FrameNode*, NodeRenderStatusHandleFunc>> outCallbacks;
94 for (const auto& [frameNode, sourceListener] : nodeRenderStatusListeners_) {
95 CHECK_NULL_VOID(frameNode);
96 auto state = GetNodeCurrentRenderState(frameNode);
97 if (sourceListener->nodeRenderState == state) {
98 continue;
99 }
100 sourceListener->nodeRenderState = state;
101 for (const auto& listener : sourceListener->nodeRenderStatusListeners) {
102 if (!listener || !listener->func) {
103 continue;
104 }
105
106 if (state == NodeRenderState::ABOUT_TO_RENDER_IN) {
107 inCallbacks.emplace_back(frameNode, listener->func);
108 } else if (state == NodeRenderState::ABOUT_TO_RENDER_OUT) {
109 outCallbacks.emplace_back(frameNode, listener->func);
110 }
111 }
112 }
113
114 for (const auto& [frameNode, func] : inCallbacks) {
115 CHECK_NULL_VOID(func);
116 func(frameNode, NodeRenderState::ABOUT_TO_RENDER_IN, RenderMonitorReason::RENDER_CHANGE);
117 }
118
119 for (const auto& [frameNode, func] : outCallbacks) {
120 CHECK_NULL_VOID(func);
121 func(frameNode, NodeRenderState::ABOUT_TO_RENDER_OUT, RenderMonitorReason::RENDER_CHANGE);
122 }
123 }
124
NotifyFrameNodeRelease(FrameNode * frameNode)125 void NodeRenderStatusMonitor::NotifyFrameNodeRelease(FrameNode* frameNode)
126 {
127 CHECK_NULL_VOID(frameNode);
128 auto it = nodeRenderStatusListeners_.find(frameNode);
129 if (it != nodeRenderStatusListeners_.end()) {
130 auto& sourceListener = it->second;
131 CHECK_NULL_VOID(sourceListener);
132 for (const auto& listener : sourceListener->nodeRenderStatusListeners) {
133 if (listener && listener->func) {
134 listener->func(frameNode, NodeRenderState::ABOUT_TO_RENDER_OUT, RenderMonitorReason::NODE_RELEASE);
135 }
136 }
137 nodeRenderStatusListeners_.erase(it);
138 }
139 }
140
IsNodeRenderOut(FrameNode * node)141 bool NodeRenderStatusMonitor::IsNodeRenderOut(FrameNode* node)
142 {
143 CHECK_NULL_RETURN(node, true);
144 return (!node->IsVisible() || !node->IsActive() || !node->IsOnMainTree());
145 }
146
GetNodeCurrentRenderState(FrameNode * frameNode)147 NodeRenderState NodeRenderStatusMonitor::GetNodeCurrentRenderState(FrameNode* frameNode)
148 {
149 CHECK_NULL_RETURN(frameNode, NodeRenderState::ABOUT_TO_RENDER_OUT);
150 if (IsNodeRenderOut(frameNode)) {
151 return NodeRenderState::ABOUT_TO_RENDER_OUT;
152 }
153 auto parent = frameNode->GetParent();
154 CHECK_NULL_RETURN(parent, NodeRenderState::ABOUT_TO_RENDER_OUT);
155 while (parent) {
156 if (AceType::InstanceOf<FrameNode>(parent)) {
157 auto node = AceType::DynamicCast<FrameNode>(parent);
158 if (node->IsRootNode()) {
159 return NodeRenderState::ABOUT_TO_RENDER_IN;
160 }
161 if (IsNodeRenderOut(AceType::RawPtr(node))) {
162 return NodeRenderState::ABOUT_TO_RENDER_OUT;
163 }
164 }
165 parent = parent->GetParent();
166 }
167 return NodeRenderState::ABOUT_TO_RENDER_OUT;
168 }
169
GenerateId()170 int32_t NodeRenderStatusMonitor::GenerateId()
171 {
172 static std::atomic<int32_t> gInstanceId;
173 int32_t id = gInstanceId.fetch_add(1);
174 return id;
175 }
176
177 } // namespace OHOS::Ace::NG