• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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