1 /*
2 * Copyright (c) 2021-2022 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 "pipeline/rs_base_render_node.h"
17
18 #include <algorithm>
19
20 #include "pipeline/rs_context.h"
21 #include "pipeline/rs_surface_render_node.h"
22 #include "platform/common/rs_log.h"
23 #include "transaction/rs_transaction_proxy.h"
24 #include "visitor/rs_node_visitor.h"
25
26 namespace OHOS {
27 namespace Rosen {
AddChild(SharedPtr child,int index)28 void RSBaseRenderNode::AddChild(SharedPtr child, int index)
29 {
30 // sanity check, avoid loop
31 if (child == nullptr || child->GetId() == GetId()) {
32 return;
33 }
34 // if child already has a parent, remove it from its previous parent
35 if (auto prevParent = child->GetParent().lock()) {
36 prevParent->RemoveChild(child);
37 }
38
39 // Set parent-child relationship
40 child->SetParent(weak_from_this());
41 if (index < 0 || index >= static_cast<int>(children_.size())) {
42 children_.emplace_back(child);
43 } else {
44 children_.emplace(std::next(children_.begin(), index), child);
45 }
46
47 disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
48 // A child is not on the tree until its parent is on the tree
49 if (isOnTheTree_) {
50 child->SetIsOnTheTree(true);
51 }
52 SetDirty();
53 }
54
MoveChild(SharedPtr child,int index)55 void RSBaseRenderNode::MoveChild(SharedPtr child, int index)
56 {
57 if (child == nullptr || child->GetParent().lock().get() != this) {
58 return;
59 }
60 auto it = std::find_if(children_.begin(), children_.end(),
61 [&](WeakPtr& ptr) -> bool { return ROSEN_EQ<RSBaseRenderNode>(ptr, child); });
62 if (it == children_.end()) {
63 return;
64 }
65
66 // Reset parent-child relationship
67 if (index < 0 || index >= static_cast<int>(children_.size())) {
68 children_.emplace_back(child);
69 } else {
70 children_.emplace(std::next(children_.begin(), index), child);
71 }
72 children_.erase(it);
73 SetDirty();
74 }
75
RemoveChild(SharedPtr child,bool skipTransition)76 void RSBaseRenderNode::RemoveChild(SharedPtr child, bool skipTransition)
77 {
78 if (child == nullptr) {
79 return;
80 }
81 // break parent-child relationship
82 auto it = std::find_if(children_.begin(), children_.end(),
83 [&](WeakPtr& ptr) -> bool { return ROSEN_EQ<RSBaseRenderNode>(ptr, child); });
84 if (it == children_.end()) {
85 return;
86 }
87 // avoid duplicate entry in disappearingChildren_ (this should not happen)
88 disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
89 // if child has disappearing transition, add it to disappearingChildren_
90 if (skipTransition == false && child->HasDisappearingTransition(true)) {
91 ROSEN_LOGD("RSBaseRenderNode::RemoveChild %" PRIu64 " move child(id %" PRIu64 ") into disappearingChildren",
92 GetId(), child->GetId());
93 // keep shared_ptr alive for transition
94 uint32_t origPos = static_cast<uint32_t>(std::distance(children_.begin(), it));
95 disappearingChildren_.emplace_back(child, origPos);
96 } else {
97 child->ResetParent();
98 }
99 children_.erase(it);
100 SetDirty();
101 }
102
SetIsOnTheTree(bool flag)103 void RSBaseRenderNode::SetIsOnTheTree(bool flag)
104 {
105 // We do not need to label a child when the child is removed from a parent that is not on the tree
106 if (!flag && !isOnTheTree_) {
107 return;
108 }
109
110 isOnTheTree_ = flag;
111 for (auto& childWeakPtr : children_) {
112 auto child = childWeakPtr.lock();
113 if (child == nullptr) {
114 continue;
115 }
116 child->SetIsOnTheTree(flag);
117 }
118
119 if (flag) {
120 return;
121 }
122
123 for (auto& childPtr : disappearingChildren_) {
124 auto child = childPtr.first;
125 if (child == nullptr) {
126 continue;
127 }
128 child->SetIsOnTheTree(flag);
129 }
130 }
131
UpdateChildrenRect(const RectI & subRect)132 void RSBaseRenderNode::UpdateChildrenRect(const RectI& subRect)
133 {
134 if (!subRect.IsEmpty()) {
135 if (childrenRect_.IsEmpty()) {
136 // init as not empty subRect in case join RectI enlarging area
137 childrenRect_ = subRect;
138 } else {
139 childrenRect_ = childrenRect_.JoinRect(subRect);
140 }
141 }
142 }
143
AddCrossParentChild(const SharedPtr & child,int32_t index)144 void RSBaseRenderNode::AddCrossParentChild(const SharedPtr& child, int32_t index)
145 {
146 // AddCrossParentChild only used as: the child is under multiple parents(e.g. a window cross multi-screens),
147 // so this child will not remove from the old parent.
148 if (child == nullptr) {
149 return;
150 }
151
152 // Set parent-child relationship
153 child->SetParent(weak_from_this());
154 if (index < 0 || index >= static_cast<int32_t>(children_.size())) {
155 children_.emplace_back(child);
156 } else {
157 children_.emplace(std::next(children_.begin(), index), child);
158 }
159
160 disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
161 // A child is not on the tree until its parent is on the tree
162 if (isOnTheTree_) {
163 child->SetIsOnTheTree(true);
164 }
165 SetDirty();
166 }
167
RemoveCrossParentChild(const SharedPtr & child,const WeakPtr & newParent)168 void RSBaseRenderNode::RemoveCrossParentChild(const SharedPtr& child, const WeakPtr& newParent)
169 {
170 // RemoveCrossParentChild only used as: the child is under multiple parents(e.g. a window cross multi-screens),
171 // set the newParentId to rebuild the parent-child relationship.
172 if (child == nullptr) {
173 return;
174 }
175 // break parent-child relationship
176 auto it = std::find_if(children_.begin(), children_.end(),
177 [&](WeakPtr& ptr) -> bool { return ROSEN_EQ<RSBaseRenderNode>(ptr, child); });
178 if (it == children_.end()) {
179 return;
180 }
181 // avoid duplicate entry in disappearingChildren_ (this should not happen)
182 disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
183 // if child has disappearing transition, add it to disappearingChildren_
184 if (child->HasDisappearingTransition(true)) {
185 ROSEN_LOGD("RSBaseRenderNode::RemoveChild %" PRIu64 " move child(id %" PRIu64 ") into disappearingChildren",
186 GetId(), child->GetId());
187 // keep shared_ptr alive for transition
188 uint32_t origPos = static_cast<uint32_t>(std::distance(children_.begin(), it));
189 disappearingChildren_.emplace_back(child, origPos);
190 } else {
191 child->SetParent(newParent);
192 // attention: set new parent means 'old' parent has removed this child
193 hasRemovedChild_ = true;
194 }
195 children_.erase(it);
196 SetDirty();
197 }
198
RemoveFromTree(bool skipTransition)199 void RSBaseRenderNode::RemoveFromTree(bool skipTransition)
200 {
201 auto parentPtr = parent_.lock();
202 if (parentPtr == nullptr) {
203 return;
204 }
205 auto child = shared_from_this();
206 parentPtr->RemoveChild(child, skipTransition);
207 if (skipTransition == false) {
208 return;
209 }
210 // force remove child from disappearingChildren_ and clean sortChildren_ cache
211 parentPtr->disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
212 parentPtr->sortedChildren_.clear();
213 child->ResetParent();
214 }
215
ClearChildren()216 void RSBaseRenderNode::ClearChildren()
217 {
218 if (children_.empty()) {
219 return;
220 }
221 // Cache the parent's transition state to avoid redundant recursively check
222 bool parentHasDisappearingTransition = HasDisappearingTransition(true);
223 uint32_t pos = 0;
224 for (auto& childWeakPtr : children_) {
225 auto child = childWeakPtr.lock();
226 if (child == nullptr) {
227 ++pos;
228 continue;
229 }
230 // avoid duplicate entry in disappearingChildren_ (this should not happen)
231 disappearingChildren_.remove_if([&child](const auto& pair) -> bool { return pair.first == child; });
232 if (parentHasDisappearingTransition || child->HasDisappearingTransition(false)) {
233 // keep shared_ptr alive for transition
234 disappearingChildren_.emplace_back(child, pos);
235 } else {
236 child->ResetParent();
237 }
238 ++pos;
239 }
240 children_.clear();
241 SetDirty();
242 }
243
SetParent(WeakPtr parent)244 void RSBaseRenderNode::SetParent(WeakPtr parent)
245 {
246 parent_ = parent;
247 }
248
ResetParent()249 void RSBaseRenderNode::ResetParent()
250 {
251 auto parentNode = parent_.lock();
252 if (parentNode) {
253 parentNode->hasRemovedChild_ = true;
254 }
255 parent_.reset();
256 SetIsOnTheTree(false);
257 }
258
GetParent() const259 RSBaseRenderNode::WeakPtr RSBaseRenderNode::GetParent() const
260 {
261 return parent_;
262 }
263
DumpTree(int32_t depth,std::string & out) const264 void RSBaseRenderNode::DumpTree(int32_t depth, std::string& out) const
265 {
266 std::string space = " ";
267 for (int32_t i = 0; i < depth; ++i) {
268 out += space;
269 }
270 out += "| ";
271 DumpNodeType(out);
272 out += "[" + std::to_string(GetId()) + "]";
273 out += ", isOnTheTree: " + std::to_string(isOnTheTree_);
274 if (GetType() == RSRenderNodeType::SURFACE_NODE) {
275 auto surfaceNode = (static_cast<const RSSurfaceRenderNode*>(this));
276 const RSSurfaceHandler& surfaceHandler = static_cast<const RSSurfaceHandler&>(*surfaceNode);
277 out += ", hasConsumer: " + std::to_string(surfaceHandler.HasConsumer());
278 out += ", Name [" + surfaceNode->GetName() + "]";
279 auto p = parent_.lock();
280 out += ", parent [" + (p != nullptr ? std::to_string(p->GetId()) : "null") + "]";
281 out = out + ", " + surfaceNode->GetVisibleRegion().GetRegionInfo();
282 out += ", SurfaceBgAlpha[ " + std::to_string(surfaceNode->GetAbilityBgAlpha()) + " ]";
283 }
284 out += ", children[";
285 for (auto child : children_) {
286 auto c = child.lock();
287 if (c != nullptr) {
288 out += std::to_string(c->GetId()) + " ";
289 } else {
290 out += ", null";
291 }
292 }
293 if (!disappearingChildren_.empty()) {
294 out += "], disappearing children[";
295 int i = 0;
296 for (auto& disappearingChild : disappearingChildren_) {
297 out += "(" + std::to_string(i) + ": id:" + std::to_string(disappearingChild.first->GetId()) +
298 ", Transition:" + std::to_string(disappearingChild.first->HasDisappearingTransition(false)) + "),";
299 ++i;
300 }
301 }
302 out += "]\n";
303
304 for (auto child : children_) {
305 if (auto c = child.lock()) {
306 c->DumpTree(depth + 1, out);
307 }
308 }
309 for (auto& child : disappearingChildren_) {
310 if (auto c = child.first) {
311 c->DumpTree(depth + 1, out);
312 }
313 }
314 }
315
DumpNodeType(std::string & out) const316 void RSBaseRenderNode::DumpNodeType(std::string& out) const
317 {
318 switch (GetType()) {
319 case RSRenderNodeType::BASE_NODE: {
320 out += "BASE_NODE";
321 break;
322 }
323 case RSRenderNodeType::DISPLAY_NODE: {
324 out += "DISPLAY_NODE";
325 break;
326 }
327 case RSRenderNodeType::RS_NODE: {
328 out += "RS_NODE";
329 break;
330 }
331 case RSRenderNodeType::SURFACE_NODE: {
332 out += "SURFACE_NODE";
333 break;
334 }
335 case RSRenderNodeType::CANVAS_NODE: {
336 out += "CANVAS_NODE";
337 break;
338 }
339 case RSRenderNodeType::ROOT_NODE: {
340 out += "ROOT_NODE";
341 break;
342 }
343 case RSRenderNodeType::PROXY_NODE: {
344 out += "PROXY_NODE";
345 break;
346 }
347 default: {
348 out += "UNKNOWN_NODE";
349 break;
350 }
351 }
352 }
353
IsDirty() const354 bool RSBaseRenderNode::IsDirty() const
355 {
356 return dirtyStatus_ == NodeDirty::DIRTY;
357 }
358
SetDirty()359 void RSBaseRenderNode::SetDirty()
360 {
361 dirtyStatus_ = NodeDirty::DIRTY;
362 }
363
SetClean()364 void RSBaseRenderNode::SetClean()
365 {
366 dirtyStatus_ = NodeDirty::CLEAN;
367 }
368
CollectSurface(const std::shared_ptr<RSBaseRenderNode> & node,std::vector<RSBaseRenderNode::SharedPtr> & vec,bool isUniRender)369 void RSBaseRenderNode::CollectSurface(
370 const std::shared_ptr<RSBaseRenderNode>& node, std::vector<RSBaseRenderNode::SharedPtr>& vec, bool isUniRender)
371 {
372 for (auto& child : node->GetSortedChildren()) {
373 child->CollectSurface(child, vec, isUniRender);
374 }
375 }
376
Prepare(const std::shared_ptr<RSNodeVisitor> & visitor)377 void RSBaseRenderNode::Prepare(const std::shared_ptr<RSNodeVisitor>& visitor)
378 {
379 if (!visitor) {
380 return;
381 }
382 visitor->PrepareBaseRenderNode(*this);
383 }
384
Process(const std::shared_ptr<RSNodeVisitor> & visitor)385 void RSBaseRenderNode::Process(const std::shared_ptr<RSNodeVisitor>& visitor)
386 {
387 if (!visitor) {
388 return;
389 }
390 visitor->ProcessBaseRenderNode(*this);
391 }
392
GetSortedChildren()393 const std::list<RSBaseRenderNode::SharedPtr>& RSBaseRenderNode::GetSortedChildren()
394 {
395 // generate sorted children list if it's empty
396 if (sortedChildren_.empty() && (!children_.empty() || !disappearingChildren_.empty())) {
397 GenerateSortedChildren();
398 }
399 return sortedChildren_;
400 }
401
GenerateSortedChildren()402 void RSBaseRenderNode::GenerateSortedChildren()
403 {
404 sortedChildren_.clear();
405
406 // Step 1: copy all existing children to sortedChildren (skip and clean expired children)
407 children_.remove_if([this](const auto& child) -> bool {
408 auto existingChild = child.lock();
409 if (existingChild == nullptr) {
410 ROSEN_LOGI("RSBaseRenderNode::GenerateSortedChildren removing expired child");
411 return true;
412 }
413 sortedChildren_.emplace_back(std::move(existingChild));
414 return false;
415 });
416
417 // Step 2: insert disappearing children into sortedChildren, at it's original position, remove if it's transition
418 // finished
419 // If exist disappearing Children, cache the parent's transition state to avoid redundant recursively check
420 bool parentHasDisappearingTransition = disappearingChildren_.empty() ? false : HasDisappearingTransition(true);
421 disappearingChildren_.remove_if([this, parentHasDisappearingTransition](const auto& pair) -> bool {
422 auto& disappearingChild = pair.first;
423 const auto& origPos = pair.second;
424 // if neither parent node or child node has transition, we can safely remove it
425 if (!parentHasDisappearingTransition && !disappearingChild->HasDisappearingTransition(false)) {
426 ROSEN_LOGD("RSBaseRenderNode::GenerateSortedChildren removing finished transition child(id %" PRIu64 ")",
427 disappearingChild->GetId());
428 if (ROSEN_EQ<RSBaseRenderNode>(disappearingChild->GetParent(), weak_from_this())) {
429 disappearingChild->ResetParent();
430 }
431 return true;
432 }
433 if (origPos < sortedChildren_.size()) {
434 sortedChildren_.emplace(std::next(sortedChildren_.begin(), origPos), disappearingChild);
435 } else {
436 sortedChildren_.emplace_back(disappearingChild);
437 }
438 return false;
439 });
440
441 // Step 3: sort all children by z-order (std::list::sort is stable)
442 sortedChildren_.sort([](const auto& first, const auto& second) -> bool {
443 auto node1 = RSBaseRenderNode::ReinterpretCast<RSRenderNode>(first);
444 auto node2 = RSBaseRenderNode::ReinterpretCast<RSRenderNode>(second);
445 if (node1 == nullptr || node2 == nullptr) {
446 return false;
447 }
448 return node1->GetRenderProperties().GetPositionZ() < node2->GetRenderProperties().GetPositionZ();
449 });
450 }
451
SendCommandFromRT(std::unique_ptr<RSCommand> & command,NodeId nodeId)452 void RSBaseRenderNode::SendCommandFromRT(std::unique_ptr<RSCommand>& command, NodeId nodeId)
453 {
454 auto transactionProxy = RSTransactionProxy::GetInstance();
455 if (transactionProxy != nullptr) {
456 transactionProxy->AddCommandFromRT(command, nodeId);
457 }
458 }
459
InternalRemoveSelfFromDisappearingChildren()460 void RSBaseRenderNode::InternalRemoveSelfFromDisappearingChildren()
461 {
462 // internal use only, force remove self from parent's disappearingChildren_
463 if (auto parent = parent_.lock()) {
464 parent->disappearingChildren_.remove_if(
465 [childPtr = shared_from_this()](const auto& pair) -> bool {
466 if (pair.first == childPtr) {
467 childPtr ->ResetParent(); // when child been removed, notify dirty by ResetParent()
468 return true;
469 } else {
470 return false;
471 }
472 }
473 );
474 }
475 }
476 } // namespace Rosen
477 } // namespace OHOS
478