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