• 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 "core/pipeline/base/rosen_render_context.h"
17 
18 #include "core/pipeline/base/render_sub_container.h"
19 #include "render_service_client/core/ui/rs_canvas_node.h"
20 
21 namespace OHOS::Ace {
22 namespace {
23 
24 constexpr int32_t OVERFLOW_PLATFORM_VERSION = 7;
25 
ShouldPaint(const RefPtr<RenderNode> & node)26 inline bool ShouldPaint(const RefPtr<RenderNode>& node)
27 {
28     return node != nullptr && node->GetVisible() && !node->GetHidden();
29 }
30 
31 } // namespace
32 
~RosenRenderContext()33 RosenRenderContext::~RosenRenderContext()
34 {
35     StopRecordingIfNeeded();
36 }
37 
Repaint(const RefPtr<RenderNode> & node)38 void RosenRenderContext::Repaint(const RefPtr<RenderNode>& node)
39 {
40     if (!ShouldPaint(node) || !node->NeedRender() || node->GetRSNode() == nullptr) {
41         return;
42     }
43 
44     auto rsNode = node->GetRSNode();
45     auto offset =
46         node->GetTransitionPaintRect().GetOffset() -
47         Offset(rsNode->GetStagingProperties().GetFrame().x_, rsNode->GetStagingProperties().GetFrame().y_);
48 
49     std::string name = AceType::TypeName(node);
50     if (name != "RosenRenderForm" && name != "RosenRenderPlugin") {
51         InitContext(rsNode, node->GetRectWithShadow(), offset);
52         node->RenderWithContext(*this, offset);
53         UpdateChildren(rsNode);
54     } else {
55         node->RenderWithContext(*this, offset);
56     }
57     StopRecordingIfNeeded();
58 }
59 
PaintChild(const RefPtr<RenderNode> & child,const Offset & offset)60 void RosenRenderContext::PaintChild(const RefPtr<RenderNode>& child, const Offset& offset)
61 {
62     if (!ShouldPaint(child)) {
63         return;
64     }
65     auto pipelineContext = child->GetContext().Upgrade();
66     if (!pipelineContext) {
67         LOGE("pipelineContext is null.");
68         return;
69     }
70     bool canChildOverflow = pipelineContext->GetMinPlatformVersion() >= OVERFLOW_PLATFORM_VERSION;
71     Rect rect = child->GetTransitionPaintRect() + offset;
72     if (!(child->IsPaintOutOfParent() || canChildOverflow) && !estimatedRect_.IsIntersectWith(rect)) {
73 #if defined(PREVIEW)
74         child->ClearAccessibilityRect();
75 #endif
76         return;
77     }
78 
79     auto childRSNode = child->GetRSNode();
80     if (childRSNode && childRSNode != rsNode_) {
81         childNodes_.emplace_back(childRSNode);
82         std::string name = AceType::TypeName(child);
83         if (name != "RosenRenderForm" && name != "RosenRenderPlugin") {
84             if (child->NeedRender()) {
85                 RosenRenderContext context;
86                 auto transparentHole = pipelineContext->GetTransparentHole();
87                 if (transparentHole.IsValid() && child->GetNeedClip()) {
88                     Offset childOffset = rect.GetOffset();
89                     Rect hole = transparentHole - childOffset;
90                     context.SetClipHole(hole);
91                 }
92                 context.Repaint(child);
93             } else {
94                 // No need to repaint, notify to update AccessibilityNode info.
95                 child->NotifyPaintFinish();
96             }
97         }
98         Offset pos = rect.GetOffset();
99         if (name == "RosenRenderPlugin") {
100             auto renderPlugin = AceType::DynamicCast<RenderSubContainer>(child);
101             if (!renderPlugin) {
102                 return;
103             }
104             auto pluginContext = renderPlugin->GetSubPipelineContext();
105             if (!pluginContext) {
106                 return;
107             }
108             auto density = pipelineContext->GetDensity();
109             Offset pluginOffset = {pos.GetX() / density, pos.GetY() / density};
110             pluginContext->SetPluginEventOffset(child->GetGlobalOffset());
111         }
112     } else {
113         child->RenderWithContext(*this, rect.GetOffset());
114     }
115 }
116 
StartRecording()117 void RosenRenderContext::StartRecording()
118 {
119     recordingCanvas_ = new Rosen::Drawing::RecordingCanvas(estimatedRect_.Width(), estimatedRect_.Height());
120     if (clipHole_.IsValid()) {
121         recordingCanvas_->Save();
122         needRestoreHole_ = true;
123         recordingCanvas_->ClipRect(
124             RSRect(clipHole_.Left(), clipHole_.Top(), clipHole_.Right(), clipHole_.Bottom()),
125             RSClipOp::DIFFERENCE, true);
126     }
127 }
128 
StopRecordingIfNeeded()129 void RosenRenderContext::StopRecordingIfNeeded()
130 {
131     auto rsCanvasNode = RSNode::ReinterpretCast<Rosen::RSCanvasNode>(rsNode_);
132     if (rosenCanvas_ && rsCanvasNode) {
133         rsCanvasNode->FinishRecording();
134         rosenCanvas_ = nullptr;
135     }
136 
137     if (needRestoreHole_) {
138         recordingCanvas_->Restore();
139         needRestoreHole_ = false;
140     }
141 
142     if (IsRecording()) {
143         delete recordingCanvas_;
144         recordingCanvas_ = nullptr;
145     }
146 }
147 
IsIntersectWith(const RefPtr<RenderNode> & child,Offset & offset)148 bool RosenRenderContext::IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset)
149 {
150     if (!ShouldPaint(child)) {
151         return false;
152     }
153 
154     Rect rect = child->GetTransitionPaintRect() + offset;
155     if (!estimatedRect_.IsIntersectWith(rect)) {
156 #if defined(PREVIEW)
157         child->ClearAccessibilityRect();
158 #endif
159         return false;
160     }
161 
162     offset = rect.GetOffset();
163     return true;
164 }
165 
InitContext(const std::shared_ptr<RSNode> & rsNode,const Rect & rect,const Offset & initialOffset)166 void RosenRenderContext::InitContext(
167     const std::shared_ptr<RSNode>& rsNode, const Rect& rect, const Offset& initialOffset)
168 {
169     rsNode_ = rsNode;
170     estimatedRect_ = rect + initialOffset;
171     if (rsNode_ == nullptr) {
172         return;
173     }
174     childNodes_.clear();
175     if (auto rsCanvasNode = rsNode_->ReinterpretCastTo<Rosen::RSCanvasNode>()) {
176         rosenCanvas_ = rsCanvasNode->BeginRecording(rsCanvasNode->GetPaintWidth(), rsCanvasNode->GetPaintHeight());
177     }
178 }
179 
GetCanvas()180 RSCanvas* RosenRenderContext::GetCanvas()
181 {
182     // if recording, return recording canvas
183     return recordingCanvas_ ? recordingCanvas_ : rosenCanvas_;
184 }
185 
GetRSNode()186 const std::shared_ptr<RSNode>& RosenRenderContext::GetRSNode()
187 {
188     return rsNode_;
189 }
190 
FinishRecordingAsPicture()191 std::shared_ptr<RSPicture> RosenRenderContext::FinishRecordingAsPicture()
192 {
193     LOGE("Drawing is not supported");
194     return nullptr;
195 }
196 
FinishRecordingAsImage()197 std::shared_ptr<RSImage> RosenRenderContext::FinishRecordingAsImage()
198 {
199     LOGE("Drawing is not supported");
200     return nullptr;
201 }
202 
Restore()203 void RosenRenderContext::Restore()
204 {
205     auto canvas = GetCanvas();
206     if (canvas != nullptr) {
207         canvas->Restore();
208     }
209 }
210 
UpdateChildren(const std::shared_ptr<RSNode> & rsNode)211 void RosenRenderContext::UpdateChildren(const std::shared_ptr<RSNode>& rsNode)
212 {
213     std::vector<OHOS::Rosen::NodeId> childNodeIds;
214     for (auto& child : childNodes_) {
215         if (auto childNode = child.lock()) {
216             childNodeIds.emplace_back(childNode->GetId());
217         }
218     }
219     if (childNodeIds != rsNode->GetChildren()) {
220         rsNode->ClearChildren();
221         for (auto& child : childNodes_) {
222             rsNode->AddChild(child.lock());
223         }
224     }
225 }
226 } // namespace OHOS::Ace
227